最近ブログネタを探すため、特に業務で使う予定はないのですがReactで少し遊んでいます。
今回はドキュメントをちゃんと読まないで遊んでいた結果、みごとにつまずいたので、その事について書いてみようかと思います。
(皆さんはドキュメントをちゃんと読みましょう!!)
対象者
さすがにReactを0から説明する気はありませんので、対象者を限定しておきたいと思います。
- htmlがわかる人
- jsがわかる人
- ECMAScript6に関して少しだけはわかる人(クラス構文、アロー関数等)
- Reactで書かれたコードの流れが読める人
※ 厳密な定義でないので、あくまで参考程度にとどめておいてください。
困ったこと
コードだけだと説明が伝わりにくいので、まずはやりたかったことを説明していきます。
やりたかったことはシンプルで、以下のGIF画像のようにボタンがクリックされた際、ボタンの文言を切り替えること、ただそれだけです。
コンポーネントを分割しないで書いてみると以下のように書けます。
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = { text: 'OFF' };
}
btnClickHandler = () => {
const changeText = this.state.text === 'OFF' ? 'ON' : 'OFF';
this.setState({ text: changeText });
};
render() {
return (
<div>
<a
className="button"
onClick={this.btnClickHandler}>{this.state.text}</a>
</div>
);
}
}
export default App;
本題と関係ないのでCSSに関しては省略したいと思います。
難しい処理はないのでコードの説明もしません。
問題は以下のようにコンポーネントを分割してみようとした際に起こりました。
class App extends Component {
// constructor, イベントハンドラーは同じため省略
render() {
return (
<div>
<CustomButton
btnClickHandler={this.btnClickHandler}
text={this.state.text} />
</div>
);
}
}
class CustomButton extends Component {
constructor(props) {
super(props);
this.state = {
text: props.text,
btnClickHandler: props.btnClickHandler
};
}
render() {
return (
<a
className="button"
onClick={this.state.btnClickHandler}>{this.state.text} />
)
}
}
こんな感じのコードを書いてしまうとボタンの状態が切り替わりません。
デバッグしたところ以下のような事がわかりました。
- ボタンがクリックされるたび、各クラスのrenderメソッドは呼ばれている。
- Appクラスのstateは期待通りに変更されているが、CustomButtonクラスのstateが変更されない。
- 各クラスのコンストラクタは1度だけ(画面初期表示時に)実行される。
stateが変更されるタイミングを確認したかったので、renderメソッドが呼ばれる前後に実行されるライフサイクルメソッドについて見てみようとしたところ、ライフサイクルメソッドの説明に入る前の概要部分にヒントとなるコードが書かれていました。
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
「もしかするとstateじゃなくてpropsだとうまくいくかも?」と思い書き換えてみると、見事に動作することができました!!
propsとstate
「propsとstateの使い分けって何?」と思いながも、先ほどのページ下部を見ていると、がっつり説明がありました。
React.Component – Instance Properties
正確な説明は公式のドキュメントにお任せするとして、違いを簡単に自分の中でまとめて今回は終わりにしようと思います。
- props
親コンポーネントから子コンポーネントに、パラメーターを受け渡すために利用される変数
子コンポーネントに受け渡したい属性値たちは、propsとして子コンポーネントに受け渡される -
state
自分自身のコンポーネントの状態を管理するために利用される変数
setStateメソッドが実行された直後に自分自身のrenderメソッドが呼ばれる
以上。