React Hooksと無限ループと再描画
問題の箇所
以下のような処理をコンポーネントの中で書いてしまいました。
const [state, setState] = useState([])
useEffect(() => {
fetch('hoge.json')
.then(response => response.json())
.then(data => setState(data))
})
何が問題か
こうすると、setState
でstate
が更新される際に、コンポーネントの再描画が走り、無限ループに陥ってしまいます。
無限ループにならないよう、マウント時にのみsetState
したいです。
対応
useEffect
の第2引数に空配列([]
)を渡してあげることで、更新時の再描画を避けることができます。
ドキュメントにはこうあります。
デフォルトの動作では、副作用関数はレンダーの完了時に毎回実行されます。これにより、コンポーネントの依存配列のうちのいずれかが変化した場合に毎回副作用が再作成されます。
-略-
これを実装するためには、useEffect の第 2 引数として、この副作用が依存している値の配列を渡します。変更後の例は以下のようになります。
-略-
空の配列 [] を渡すと、この副作用がコンポーネント内のどの値にも依存していないということを React に伝えることになります。つまり副作用はマウント時に実行されアンマウント時にクリーンアップされますが、更新時には実行されないようになります。
教訓
コンポーネント再描画のタイミングを意識するようにしよう。
また、無限ループが走ってPCが重くなっているときにPCの不具合かと思ってしまった。自分を常に疑うべし。