公式ドキュメント React.Component を読んだメモです。
コンポーネントのライフサイクルと、実行されるメソッド
React Lifecycle Methods Diagram より。
太字が主要なライフサイクルメソッド。constructor()
、render()
、componentDidMount()
、componentDidUpdate()
、componentWillUnmount()
。
前提
props
は、コンポーネントの外から来る値。親コンポーネントから受け継ぐ。変更不可。
state
はコンポーネント内のプライベートな値。変更可。この state
は Redux の state とは別物。コンポーネントの状態。
両方の値がレンダリング結果に影響する。
主要なライフサイクルメソッドの役割
constructor(props)
2つの用途にのみ使う。
-
this.state
の初期化 - イベントハンドラの
bind
constructor(props) {
super(props);
// ここで this.setState() を使ってはいけない
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
-
props
をthis.state
にコピーしてはダメ -
this.state
に直接代入していいのは、コンストラクタのみ。他はthis.setState()
を使う - コンストラクタで副作用を発生させないこと。そういう時は
componentDidMount()
を使う
render()
コンポーネントで唯一の必須メソッド。
this.props
と this.state
を読んで、以下のどれかを返す。
- React elements - JSX などで作る
- Arrays and fragments - 複数の elements を返す
- Portals - 別の DOM ノードにレンダリングする
- String and numbers - テキストとしてレンダリングする
-
Booleans or null - なにもレンダリングしない。
return test && <Child />
のtest
がfalse
の場合、Boolean
が返って何もレンダリングしない
render()
は pure な function であるべき。
- コンポーネントの state を変えない
- 同じ入力に対して毎回同じ結果を返す
- ブラウザと直接インタラクトしない。インタラクトするには
componentDidMount()
など他のメソッドを使う
shouldComponentUpdate()
が false
を返したら実行されない。
componentDidMount()
- コンポーネントがツリーにマウントされた時に実行される
- DOM ノードが必要になるような初期化処理はここでやる
- ネットワークへのリクエストをここでやる
- subscription をここでやって、
componentWillUnmount()
で unsubscribe する
componentDidMount()
で setState()
を実行すると追加のレンダリングが実行される。この時、ブラウザが画面を連続して描画したりはしない。2回 render()
が実行されても、途中の画面の変化をユーザが目にすることはない。
画面が変わらなくても、パフォーマンスには影響するので注意。
componentDidUpdate(prevProps, prevState, snapshot)
- 初回は実行されない。更新時に実行される
- コンポーネントが更新されたタイミングで DOM を操作したいときは、ここでやる
- 更新前後の props を比較して、ネットワークにリクエストしたいときは、ここでやる
-
setState()
を実行するときは、条件を設定する。条件無しだとループする- レンダリング →
setState()
→ レンダリング →setState()
→ …
- レンダリング →
-
componentDidMount()
と同じく、再レンダリングの過程は画面に描画されないけれども、パフォーマンスには影響し得る
componentWillUnmount()
- コンポーネントがアンマウントされるときに実行される
- クリーンアップの処理をここでやる
- タイマーの無効化
- ネットワークリクエストのキャンセル
- unsubscribe
- もうレンダリングされないので、
setState()
を呼んではいけない
レアなライフサイクルメソッド
shouldComponentUpdate(nextProps, nextState)
パフォーマンスの目的でのみ使用する。
今のところ、false を返すとレンダリングが実行されないが、将来は、場合によってレンダリングするように変更される可能性がある。このメソッドの結果が、厳密な制御ではなくヒントとして使われるようになる可能性がある。
getDerivedStateFromProps(props, state)
使わない。
getSnapshotBeforeUpdate(prevProps, prevState)
DOM が変化する前の値をとっておいて、componentDidUpdate(prevProps, prevState, snapshot)
の3番目の引数で受け取って使う。
Redux と一緒に使う場合
Redux と一緒に使う場合、ライフサイクルメソッドの componentDidMount
、componentDidUpdate
、componentWillUnmount
から、アクションを dispatch
できる。
render
→ componentDidMount
→ (Redux の) state 変更 → render
のように 2回レンダリングすることになるが、受け入れる。2回 render()
しても、画面の書き換えは1回だけ。