React Effect Hooksの覚え書き(基本)
はじめに
Effect Hooks はReact16.8から導入された機能です。
Function Component に対して、Class ComponentのcomponentDidMount
やcomponentWillUnmount
などに相当する処理を実装する場合に使用します。
useEffectを使うたびにcomponentDiMount
とcomponentWillUnmount
の使い分けについて調べている気がしたので、いい加減まとめておきます。
React Component の Lifecycle
React の Lifecycleは大まかにMount
, Update
, Unmount
のサイクルに大別されます。
Mountサイクル
ComponentのインスタンスがDOMに挿入される際のサイクルになります。
Updateサイクル
Props
や State
の変更によって再レンダリングが発生する場合のサイクルになります。
Unmountサイクル
Componentが DOM から削除されるときのサイクルになります。
各VersionにおけるLifecycleを確認する場合には、公式で紹介されているこちらのサイトが便利です。
Effect Hooksが与える副作用
これについては、公式サイトに名言されています。
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
--- Reactクラスのライフサイクルメソッドに慣れている方は、useEffect HookをcomponentDidMount、componentDidUpdate、componentWillUnmountを組み合わせたものと考えることができます。---
Class components における componentDidMount
、componentDidUpdate
、componentWillUnmount
の役割を担うことができます。
公式サイトのサンプルコードを参考に、 componentDidMount
、componentDidUpdate
、componentWillUnmount
を実装したClassとFunction Componentを↓に記載します。
やっていることは少し奇妙ですが、ButtonをClickすることでドキュメントタイトルを切り替えています。
import React from 'react'; import ReactDOM from 'react-dom'; interface Props {} interface State { count: number; } class ClassComponent extends React.Component<Props, State> { constructor(props: Props) { super(props); this.state = { count: 1 } } componentDidMount() { document.title = `Called MountFunc!!`; } componentDidUpdate() { document.title = `Called UpdateFunc!! Cnt = ${this.state.count}`; } componentWillUnmount() { console.log("Called UnmountFunc"); } setCount() { this.setState({ count: this.state.count + 1}); } render() { return ( <div> <h1>Counter</h1> <button onClick={_ => this.setCount()}>Click</button> </div>); } } ReactDOM.render( <React.StrictMode> <ClassComponent /> </React.StrictMode>, document.getElementById('root') );
Class Componentの場合は、componentDidMount
、componentDidUpdate
、componentWillUnmount
をそれぞれ実装することで、Lifecycleに応じて処理を実行することができます。
import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; interface Props {} function FunctionComponent(props: Props) { const [count, setCount] = useState(1); const initState = 1; useEffect(() => { // componentDidMount & componentDidUpdate if (initState === count) { // componentDidMount専用 document.title = `Called MountFunc!!`; } else { // componentDidUpdate専用 document.title = `Called UpdateFunc!! Cnt = ${count}`; } // 戻り値として、componentWillUnmount return console.log("Called UnmountFunc"); }) return ( <div> <h1>Counter</h1> <button onClick={_ => setCount(count + 1)}>Click</button> </div> ); } ReactDOM.render( <React.StrictMode> <FunctionComponent /> </React.StrictMode>, document.getElementById('root') );
Function Componentの場合は、useEffectだけでcomponentDidMount
、componentDidUpdate
、componentWillUnmount
を表現する必要があります。
componentDidMount
、componentDidUpdate
はuseEffectに引き渡す関数本体に処理を記載することで表現できます。
今回は、MountサイクルとUpdateサイクルを分けて表現したかったので、初期ステータスと比較して呼び出す処理を変更しています。
componentWillUnmount
は、useEffectの戻り値として、関数を返却することで表現することができます。
単純に使うだけであればこれだけOKですが、レンダリング毎のuseEffectの抑制や、Mount & Unmount時のみの実行などチューニングを行う場合には、より複雑になるのでそれはまた次の機会にします。
まとめ
- useEffectを使うことで、関数コンポーネントでも
componentDidMount
、componentDidUpdate
、componentWillUnmount
に相応する作用をもたらすことができる。 - useEffectを使うことで、より細かなチューニングも行うことができる。