useStateについて
-
useStateは「状態の値」と「その状態を更新する関数」を配列で返す
上記の例では、分割代入を使って、状態の値としてcount、その状態を更新する関数としてsetCountを受け取る -
React の state 更新は即時に反映されない。React は state の更新をまとめて処理するため、 同じレンダリング中では count の値が変わらないことがある。
宣言例
const [count, setCount] = React.useState(0);
問題のある例
setCount(count + 1);
setCount(count + 1);
期待する結果
0 → 2
実際の結果
0 → 1
なぜこうなるのか
setCount は state を即座に更新するのではなく、
更新処理を一旦キューに積んでからまとめて実行する。
そのため、上記のコードでは両方の setCount が
同じ count(古い値) を参照してしまう。
内部的には次のような処理と同じ意味になる。
setCount(0 + 1);
setCount(0 + 1);
結果として、最後の更新結果である 1 が state にセットされる。
安全な例
//アロー関数を省略
setCount(prev => prev + 1);
- prev は React が管理している 最新の state(prevCountなどでもOK)
- 前の state を元にして新しい state を計算する
- この関数は自分で実行しているわけではなく、React が内部で実行するため安全に更新できる。
useRefについて
-
useRefは .current プロパティを持つオブジェクト を生成するフックで、
再レンダリングが起きても 同じ参照を保持し続ける 特徴がある。 - 主な用途の一つとして、DOM要素を直接参照することができる。
使用例(input要素を参照してフォーカスする場合)
const inputRef = React.useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
inputRef.current.focus();
};
<form onSubmit={handleSubmit}>
<input ref={inputRef}/>
</form>
この例では、
- useRef(null) により ref オブジェクトを作成
- ref={inputRef} を指定することで input 要素が inputRef.current に代入される
- inputRef.current.focus() によって input 要素にフォーカスを当てている
useEffectについて
- 関数に副作用(タイミング付きの処理)を持たせるフック
useEffect(() => {
// 実行したい処理
}, [依存配列]);
*「依存配列の中の値が変わったら、この関数を実行する」
- 依存配列が空の場合([])は変化を監視する値がないのでコンポーネントが最初に表示されたとき(マウント時)に1度だけ実行される
useEffect(() => {
console.log('todosが変わった');
}, [todos]);
上記のように書いた場合
- 初回レンダリング時→実行される
- todosが変わるたび→実行される