いよいよReactの真骨頂っぽいところに足を突っ込んでみます。前回はComponentの中にComponentが1つだけ内包されていましたが、これを複数にしてみたいと思います。
西暦・和暦 相互変換Component
今年の5月には新しい年号が爆誕するのにちなんで、西暦と和暦を相互に変換するComponentを作成してみたいと思います。今回も公式ドキュメントのサンプルを改変した物になります。
実行すると昭和、平成、西暦の3つのテキストボックスが表示されます。いずれか1つに入力すると残りの2つが連動して変化します。コードがちょっと長いのですが、理解のしやすさを優先しただけで実際にやってることは大したことありません。
サンプル
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>HeiseiConvert</title>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- Don't use this in production: -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
class YearInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onYearChange(e.target.value);
}
render() {
const year = this.props.year;
const type = this.props.type;
return (
<fieldset>
<legend>{type}:</legend>
<input value={year}
placeholder={this.props.placeholder}
onChange={this.handleChange} />
年
</fieldset>
);
}
}
class HeiseiConvert extends React.Component {
constructor(props) {
super(props);
this.state = {
ad: "",
showa: "",
heisei: ""
};
this.handleAdChange = this.handleAdChange.bind(this);
this.handleShowaChange = this.handleShowaChange.bind(this);
this.handleHeiseiChange = this.handleHeiseiChange.bind(this);
}
handleAdChange(year) {
this.setState({
ad: year,
showa: this.toConvert(year, -1925),
heisei: this.toConvert(year, -1989)
});
}
handleShowaChange(year) {
this.setState({
ad: this.toConvert(year, 1925),
showa: year,
heisei: this.toConvert(year, -63)
});
}
handleHeiseiChange(year) {
this.setState({
ad: this.toConvert(year, 1988),
showa: this.toConvert(year, 63),
heisei: year
});
}
toConvert(year, value){
if( Number.isNaN(parseFloat(year)) ){
return('');
}
return( Number(year) + value);
}
render() {
return (
<div>
<YearInput
type="昭和"
placeholder="例: 64"
year={this.state.showa}
onYearChange={this.handleShowaChange} />
<YearInput
type="平成"
placeholder="例: 30"
year={this.state.heisei}
onYearChange={this.handleHeiseiChange} />
<YearInput
type="西暦"
placeholder="例: 2019"
year={this.state.ad}
onYearChange={this.handleAdChange} />
</div>
);
}
}
ReactDOM.render(
<HeiseiConvert />,
document.getElementById('root')
);
</script>
</body>
</html>
実行結果
解説
状態もイベントも親が管理する
思想はシンプルで、入力などは子供のComponentに任せていますがデータの管理はすべて親のComponentであるHeiseiConvert
が行っています。テキストボックスに入力された値は最終的にすべて以下のconstructorで初期化しているこのStateに保管されます。
class HeiseiConvert extends React.Component {
constructor(props) {
super(props);
// 状態はすべて以下のStateに入る
this.state = {
ad: "",
showa: "",
heisei: ""
};
イベントも同様です。子供のComponentであるYearInput
でテキストボックスが作成されていますが、onChange
イベントで呼び出されるのは、最終的に親で定義されているメソッドです。
render() {
const year = this.props.year;
const type = this.props.type;
return (
<fieldset>
<legend>{type}:</legend>
<input value={year}
placeholder={this.props.placeholder}
onChange={this.handleChange} />
年
</fieldset>
);
}
}
上記の onChange={this.handleChange}
から呼び出されているメソッドを見ると、Propsで親から渡されたメソッドを実行していることがわかります。
handleChange(e) {
this.props.onYearChange(e.target.value);
}
親が子供のComponentを作成している箇所を見てみると、以下のように親クラス内にあるhandleShowaChange
メソッドを渡しています。
<YearInput
type="昭和"
placeholder="例: 64"
year={this.state.showa}
onYearChange={this.handleShowaChange} />
最終的にhandleShowaChange
メソッドが親のStateを更新しているというわけです。
handleShowaChange(year) {
this.setState({
ad: this.toConvert(year, 1925),
showa: year,
heisei: this.toConvert(year, -63)
});
}
リフティング
公式ドキュメントでは「リフティング」(持ち上げる)という単語が使われていますが、これがイメージとしてわかりやすい。
イベントが発生すると子供はデータを親に対して蹴り上げるます。蹴り上げたデータを親が受け取りStateを更新すると、render()
が実行され子供が最新の状態に更新される…つまり親に向かって蹴り上げたボールが再度子供に対して落ちてくる。
以下の図はイメージです。Reactではこの流れをひたすら繰り返す、言わばサッカーのリフティングのような動きを行っているというわけです。
書籍
翔泳社
売り上げランキング: 139,067
参考ページ
このブログを応援する
お寄せいただいたお気持ちは全額サーバ代や次の記事を執筆するための原資として活用させていただいております。この記事が参考になった場合などぜひご検討ください。
同じカテゴリの記事
- はじめてのReact #30 「CSSフレームワークを導入する」Material-UI テーマをカスタマイズ編
- はじめてのReact #29 「CSSフレームワークを導入する」Material-UI アイコンと文字スタイル編
- はじめてのReact #28 「CSSフレームワークを導入する」Material-UI グリッド編
- はじめてのReact #27 「CSSフレームワークを導入する」Material-UI インストール編
- はじめてのReact #26 「ルーティングに対応する」設定をJSONにまとめる編 react-router@v5
- はじめてのReact #25 「ルーティングに対応する」認証とリダイレクト編 react-router@v5
- はじめてのReact #24 「ルーティングに対応する」URLパラメーター編 react-router@v5
- はじめてのReact #23 「ルーティングに対応する」基本編 react-router@v5