私はReactを学習していて、useEffect
から返された関数はクリーンアップを行うことを意図しており、Reactがコンポーネントがアンマウントされます。
だから私はそれを少し実験しましたが、次の例では、DOMからマウント解除されたときだけではなく、コンポーネントが再レンダリングされるたびに関数が呼び出されることを発見しました。つまり、毎回console.log("unmount");
コンポーネントの再レンダリング。
何故ですか?
function Something({ setShow }) {
const [array, setArray] = useState([]);
const myRef = useRef(null);
useEffect(() => {
const id = setInterval(() => {
setArray(array.concat("hello"));
}, 3000);
myRef.current = id;
return () => {
console.log("unmount");
clearInterval(myRef.current);
};
}, [array]);
const unmount = () => {
setShow(false);
};
return (
<div>
{array.map((item, index) => {
return (
<p key={index}>
{Array(index + 1)
.fill(item)
.join("")}
</p>
);
})}
<button onClick={() => unmount()}>close</button>
</div>
);
}
function App() {
const [show, setShow] = useState(true);
return show ? <Something setShow={setShow} /> : null;
}
コードを見ると、2番目のパラメーター[array]
が原因であると推測できます。あなたはそれを更新しているので、それは再レンダリングを呼び出します。空の配列を設定してみてください。
状態を更新するたびに再レンダリングとアンマウントが呼び出され、その配列は変化します。
React docsには 説明セクション が正確にあります。
要するに、そのような設計は古いデータと更新のバグから保護するためです。
ReactのuseEffect
フックは、最初のレンダリングと後続のレンダリングの両方を処理するように設計されています( 詳細はこちら )。
効果は、それらを使用するコンポーネントのライフサイクルではなく、依存関係によって制御されます。
エフェクトの依存関係が変更されると、useEffect
は以前のエフェクトをクリーンアップし、新しいエフェクトを実行します。
そのようなデザインはより予測可能です- 各レンダリングには独自の(純粋な)動作効果があります 。これにより、UIに常に正しいデータが表示されるようになります(ReactのメンタルモデルのUIは特定のレンダリングの状態のスクリーンショットであるため)。
私たちが効果を制御する方法は、その依存関係によるものです。
すべてのレンダリングでクリーンアップが実行されないようにするには、エフェクトの依存関係を変更しないでください。
具体的には、array
が変更されているため、クリーンアップが行われています。つまり、Object.is(oldArray, newArray) === false
useEffect(() => {
// ...
}, [array]);
// ^^^^^ you're changing the dependency of the effect
次の行でこの変更を引き起こしています。
useEffect(() => {
const id = setInterval(() => {
setArray(array.concat("hello")); // <-- changing the array changes the effect dep
}, 3000);
myRef.current = id;
return () => {
clearInterval(myRef.current);
};
}, [array]); // <-- the array is the effect dep
予想通りです。ここのドキュメントに従って、useAffects
は最初のレンダリング、すべての更新およびアンマウント後に呼び出されます。
https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
ヒント
Reactクラスのライフサイクルメソッドに精通している場合は、useEffect Hookを、componentDidMount、componentDidUpdateの前、およびcomponentWillUnmountを組み合わせたものと考えることができます。