React Hooks
React Hook を用いると state などの React の機能をクラスを書かずに関数で使うことができます。
useState
useState
を呼び出すことで、関数で state を扱うことができます。useState
の引数には state の初期値を渡します。また useState は現在の stateとそれを更新するための関数を返します。
import React, { useState } from "react";
const MessageBox = () => {
const [message, setMessage] = useState("default");
return (
<div>
<p>Your message: {message}</p>
<input type="text" onChange={e => setMessage(e.target.value)} />
</div>
);
};
useEffect
関数コンポーネント内で副作用(データの取得、subscription の設定、DOM の変更など)を行うことを実行することができます。
ライフサイクルの観点では、 useEffect
をcomponentDidMount
と componentDidUpdate
と componentWillUnmount
がまとまったものだと考えてよいです。
import React, { useState, useEffect } from "react";
const MessageBox = () => {
const [message, setMessage] = useState("default");
useEffect(() => {
console.log(`Your message: ${message}`);
});
return (
<div>
<p>Your message: {message}</p>
<input type="text" onChange={e => setMessage(e.target.value)} />
</div>
);
};
上記の例の場合、 useEffect
は初回を含むレンダー毎に呼び出されます(クラスコンポーネントの場合、componentDidMount と componentDidUpdate 両方に相当)
クリーンアップ
useEffect
内でクリーンナップするための関数を返すことができます。クリーンアップのタイミングはコンポーネントがアンマウントされる時(クラスコンポーネントでのcomponentWillUnmount
)です。
useEffect(() => {
console.log(`Your message: ${message}`);
return function cleanUp() {
// クリーンアップする処理
};
});
useEffect
は複数呼び出すことができ、ロジックを分けることもできます。
条件付きで useEffect を実行
useEffect
の第二引数に依存している値の配列を渡します(複数渡すことも可)。以下の例だと、message が変更された時のみuseEffect
が実行されます。
useEffect(() => {
console.log(`Your message: ${message}`);
return function cleanUp() {
// クリーンアップする処理
};
}, [message]);
- 第二引数に空配列[]を渡すと、どの値にも依存していないということになり、更新時に
useEffect
が実行されなくなる
useContext
import React, { useContext } from "react";
const SampleContext = React.createContext("hoge");
function HookContext() {
return (
<SampleContext.Provider value="fuga">
<Bar />
</SampleContext.Provider>
);
}
function Bar() {
return (
<div>
<Button />
</div>
);
}
function Button() {
// コンテキストオブジェクトの値を取得する
const text = useContext(SampleContext);
return <>Context Value: {text}</>;
}
useContext
は最も近いコンテキストオブジェクトの値(<MyContext.Provider>
のvalue
)を返し、引数にはコンテキストオブジェクトそのものを渡します。
useReducer
const [state, dispatch] = useReducer(reducer, initialArg);
useState
の代わりとなり、引数に
reducer
: 現在の state とアクションを受け取り、新しい state を返す関数initialState
: state の初期値
を取り、現在のstate
とdispatch
メソッド(アクションを発火する関数)を返します。
useState
に代わって使用するのは、state を前の state に基づいて更新する場合、state に依存するロジックを用いる場合などです。
例
import React, { useReducer } from "react";
const initialState = { count: 0 };
// reducerにロジックを詰め込む
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
// reducerと初期値を引数に代入し、stateとdispatchを返す
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
</>
);
}
useMemo
const CalculateMemo = useMemo(() => computeValue(x, y, z), [x, y, z]);
useMemo
は関数とそれに依存する値の配列を引数にもち、メモ化した値を返します。第二引数の配列の要素が変化した場合のみメモ化した値を再計算します。
メモ化とは、計算結果を保持して、それを再利用する手法であり、パフォーマンスの向上が期待できます。
useCallback
const CalculateCallback = useCallback(() => computeValue(x, y, z), [x, y, z]);
関数とそれに依存する値の配列を引数にもち、メモ化したコールバック関数を返します。
Hook のルール
以下、Hook のルールについて述べます。
- フックを呼び出すのは関数のトップレベルのみ
- ループや条件分岐・ネストされた関数内で呼び出してはいけない
- React はフックが呼ばれる順番に依存しているため、条件分岐等で順番が変わると state の割り当てが変わる恐れがある
- フックを呼び出すのは React の関数内のみ
eslint-plugin-react-hooks
という ESLint のプラグインを導入することでこれらのルールを強制できる