はじめに
このシリーズは、Reactの公式ページなどから特に重要と感じたトピックを選び出し、何度でも読み返せるよう簡潔にまとめたものです。
進捗管理には「いいね」か「ブックマーク」がお勧め
さらに僕のモチベーションアップになります!よろしくお願いいたします!
stateで定義したオブジェクトを直接更新してはいけない理由
このパターンはレンダリングされる?-①
下記のコードで表示されたボタンを押した時に、画面は最新の値でレンダリングされるでしょうか?
export default function ObjectState() {
const [position, setPosition] = useState({
x: 0,
y: 0
});
return (
<>
<button
onClick={() => {
position.x = position.x+1;
position.y = position.y+1;
}}>up
</button>
<div>
{position.x}
</div>
</>
);
}
結果はレンダリングされません。
レンダリングされない理由は、setPosition関数を利用していないためです。オブジェクト自体の参照値を見ているため、オブジェクトの中身を直接変更してもReactはその変更を検知しません。このため、上記の更新方法はやめましょう。
更新例〜スプレット構文を使う〜
setPosition({
...position,
y: e.clientY
});
更新例〜ローカルミューテーションを利用した更新〜
const nextPosition = {};
nextPosition.x = e.clientX;
nextPosition.y = e.clientY;
setPosition(nextPosition);
##このパターンはレンダリングされる?-②
下記のパターンは再レンダリングされるでしょうか?
import { useRef ,useState } from 'react';
export default function Counter() {
let countRef = useRef(0);
const [count, setCount] = useState(0);
function handleClick() {
// This doesn't re-render the component!
countRef.current = countRef.current + 1;
setCount(0);
}
return (
<button onClick={handleClick}>
You clicked {countRef.current} times
</button>
);
}
答えは再レンダリングされません。
handleClickでsetCountを使っているから再レンダリングされるのでは?となりますがReactは前回の値と比較し変化しなければレンダリングのトリガーにはせずレンダリングをスキップします。
ローカル変数はレンダー間で保持されない
hooksでuseStateやuseRefを使う理由の一つは、レンダー間で値を保持することです。
ローカル変数は、レンダリング間で保持されないため初期値に戻され、
useStateのようなレンダリングのトリガーがないため変更に気づけません。
下記のような処理を書いてもレンダリングはされないため注意しましょう。
let count = 0; // 再レンダリングされると初期化されます
function handleClick() {
count = count + 1;
}
<button onClick={handleClick}>
next
<button/>
{/* 値の変更がトリガにならないため描画される値は変わりません */}
<div>{count + 1}<div/>
(参考ページ参照)ボタンをクリックしてカウントを上げていっても表示は変わらない。また、修正して再レンダリングが始まるとカウントは0に初期化されます。
参考サイト
より詳しく学びたい方はこちら