これは
Reactのガイドを読んでいく記事です。
ガイドのリンク
state とライフサイクル
昨日の続き。
state を正しく使用する
setState()について
stateを直接変更しないこと
コンポーネントの再レンダーのためにはsetState()を使用する。
// これは再レンダーされない // this.stateに直接代入して良いのはコンストラクタのみ。 this.state.hoge = 'Hey'; // 正しい方法 this.setState({hoge: 'Hey'});
stateの更新は非同期に行われる可能性がある
Reactはパフォーマンスのために複数のsetState()の呼び出しを1度にまとめて処理することがあり、this.propsとthis.stateは非同期に処理されるので次のstateを求める際に結果の値を期待するような作りをするとうまく動かないことがあります。
絶対というわけではないため気付きにくいように思うが、前提として理解しておけば失敗することも少ないと思うし、真っ先に疑うべき所として意識しやすい。
以下のコードは更新に失敗する可能性がある。
this.setState({ // propsとstateの値を計算しているので更新にこける可能性がある counter: this.state.counter + this.props.increment, });
対策としてsetState()の使い方を変更する。
setState() を呼び出した直後に this.state を読み取ることが潜在的な危険になります。代わりに、componentDidUpdate または setState コールバック(setState(updater, callback))を使用してください。どちらも更新が適用された後に起動することが保証されています。
変更したコードは以下のようになる。
this.setState((state, props) => ({ counter: state.counter + props.increment }));
アロー関数ではなく以下のような通常の関数でも可能。
this.setState(function(state, propos) { return { counter: state.counter + props.increment }; });
stateの更新はマージされる
setState()を呼び出すとReactは与えられたオブジェクトを現在のstateにマージする。
setState()に複数の変数を含んでいる場合、別々のstState呼び出しで、独立して更新することが可能。
// このように3つの変数を含んでいた場合でも setState() = { A B C } componentDidMount() { // Aだけ fetchPosts().then(response => { this.setState({ A }); }); // Cだけ fetchComments().then(response => { this.setState({ C }); }); }
データは下方向に伝わる
以下のようにコンポーネントは子コンポーネントにpropsとしてstateを渡すことができる。
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
また、ユーザ定義のコンポーネントでも動作可能。
以下のFormattedDateはprops経由でdateを受け取るが、それがどこからきたものなのかはわからない。
<FormattedDate date={this.state.date} />
以上のことから、特定の他のコンポーネントがステートフルかステートレスか知ることはできないし、特定のコンポーネントの定義をきにするべきではない。
stateはローカルのものと言われ、stateは所有してセットするコンポーネント以外からのアクセスは不可。
こういったデータフローをトップダウンと呼び、全てのstateは必ず特定のコンポーネントが有し、データ、UIはツリーでそれらの下に居るコンポーネントのみに影響する。
コンポーネントツリーとは props が流れ落ちる滝なのだと想像すると、各コンポーネントの state とは任意の場所で合流してくる追加の水源であり、それらもまた下に流れ落ちていくものなのです。
とてもわかりやすい。
ドキュメント内にあったサンプルは以下。
https://codepen.io/gaearon/details/vXdGmd
今日はここまで。