1. 要素の出しわけでrenderが走っている
もし第二引数を空[]
にしても予期しないuseEffect
が走る場合は、要素が新たに表示されてrenderが走っている可能性あり。
下記のような方法で子コンポーネントが表示、非表示されていないか確認する。
子コンポーネント側でuseEffectを使用している場合に予期しないuseEffectが走る可能性がある。
import React, { useState, useEffect } from 'react';
function ParentComponent() {
const [showChild, setShowChild] = useState(false);
const handleClick = () => {
setShowChild(!showChild);
};
return (
<div>
<button onClick={handleClick}>
{showChild ? 'Hide Child' : 'Show Child'}
</button>
{showChild && <ChildComponent />}
</div>
);
}
function ChildComponent() {
useEffect(() => {
console.log('ChildComponent rendered');
}, []);
return <div>This is the child component.</div>;
}
2. render毎に新しいobjectが作られている
同列のstateが変更した時に、再renderするのだがuseEffectの第二引数がrenderの度に違うobjectとして生成されている。
下記の例だと、ageとnameの値が変わらなかったとしてもrenderの度に新しいperson
としてobjectが生成される。そのためperson
に関係ないsetDarkMode
をした時もuseEffectが走ってしまう。
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [age, setAge] = useState(0);
const [name, setName] = useState("");
const [darkMode, setDarkMode] = useState(false);
// renderの度に新しいperson objectを生成
const person = { age, name };
useEffect(() => {
// darkModeが変わった時にも呼ばれる
// personが毎回違うobjectとして認識されるため
console.log(person);
}, [person]);
const appStyle = {
backgroundColor: darkMode ? "black" : "white",
color: darkMode ? "white" : "black",
};
return (
<div style={appStyle}>
<label>Name:</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<br />
<label htmlFor="age-input">Age:</label>
<input
type="number"
value={age ?? ""}
onChange={(e) => setAge(e.target.value)}
/>
<br />
<label>Dark Mode:</label>
<input
type="checkbox"
checked={darkMode}
onChange={() => setDarkMode((prev) => !prev)}
/>
</div>
);
}
export default App;
上記にて、checkBox押した時にuseEffect
を動かしたくない場合はuseMemoを使ってname
かage
が変更された時のみ新しいobjectを生成するようにすれば良い。
import { useEffect, useState, useMemo } from "react";
import "./App.css";
function App() {
const [age, setAge] = useState(0);
const [name, setName] = useState("");
const [darkMode, setDarkMode] = useState(false);
// personをuseMemo化することによってageとnameが変わった時のみ新しいobjectを生成するようにする
const person = useMemo(() => {
return { age, name };
}, [age, name]);
useEffect(() => {
// darkModeが変わった時に呼ばれなくなる
// ageとnameが変わった時のみpersonが生成されるため
console.log(person);
}, [person]);
const appStyle = {
backgroundColor: darkMode ? "black" : "white",
color: darkMode ? "white" : "black",
};
return (
<div style={appStyle}>
<label>Name:</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<br />
<label htmlFor="age-input">Age:</label>
<input
type="number"
value={age ?? ""}
onChange={(e) => setAge(e.target.value)}
/>
<br />
<label>Dark Mode:</label>
<input
type="checkbox"
checked={darkMode}
onChange={() => setDarkMode((prev) => !prev)}
/>
</div>
);
}
export default App;