【フロントエンドエンジニア必見】React useEffect フックの最初のレンダリングを制御してパフォーマンスを向上させる
React useEffect フックを最初のレンダリングで実行しないようにする方法
空の依存関係配列を使用する
useEffect フックの第二引数に空の配列を渡すことで、最初のレンダリング時にのみ実行される副作用を作ることができます。これは、単純で分かりやすい方法ですが、useEffect 内で依存関係のある変数を直接参照できないという制限があります。
useEffect(() => {
// 最初のレンダリング時にのみ実行される副作用
}, []);
useRef Hook を使って、初回レンダリング済みフラグを管理することができます。
const isInitialRender = useRef(true);
useEffect(() => {
if (isInitialRender.current) {
// 最初のレンダリング時にのみ実行される副作用
isInitialRender.current = false;
} else {
// 依存関係の値が更新された時に実行される副作用
}
}, [someDependency]);
カスタムフックを作成する
上記の方法を抽象化して、再利用可能なカスタムフックを作成することができます。
const use初回レンダリング時のみ実行 = (callback) => {
const isInitialRender = useRef(true);
useEffect(() => {
if (isInitialRender.current) {
callback();
isInitialRender.current = false;
}
}, []);
};
// 使用例
use初回レンダリング時のみ実行(() => {
// 最初のレンダリング時にのみ実行される副作用
});
useEffect の代わりに useLayoutEffect を使用する
useLayoutEffect フックは、ブラウザのレイアウト更新後に実行される副作用を定義するために使用されます。useEffect と同様に、依存関係の配列を渡すことで、依存関係の値が更新されたタイミングで実行される副作用を作ることができます。
useLayoutEffect(() => {
// 最初のレンダリング時と、依存関係の値が更新されたタイミングで実行される副作用
}, [someDependency]);
注意点: useLayoutEffect は、レンダリングパフォーマンスに影響を与える可能性があります。必要最低限のタイミングでのみ使用することが重要です。
useEffect フックを最初のレンダリングで実行しない方法はいくつかあります。それぞれの方法にはメリットとデメリットがあり、状況に応じて最適な方法を選択する必要があります。
空の依存関係配列を使用する
const App = () => {
const [count, setCount] = useState(0);
useEffect(() => {
// 最初のレンダリング時にのみ実行される副作用
console.log('useEffect が実行されました');
}, []);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>カウントを増やす</button>
</div>
);
};
export default App;
useRef Hook を使用する
const App = () => {
const [count, setCount] = useState(0);
const isInitialRender = useRef(true);
useEffect(() => {
if (isInitialRender.current) {
// 最初のレンダリング時にのみ実行される副作用
console.log('useEffect が実行されました');
isInitialRender.current = false;
} else {
// 依存関係の値が更新された時に実行される副作用
console.log('カウントが更新されました');
}
}, [count]);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>カウントを増やす</button>
</div>
);
};
export default App;
カスタムフックを作成する
const use初回レンダリング時のみ実行 = (callback) => {
const isInitialRender = useRef(true);
useEffect(() => {
if (isInitialRender.current) {
callback();
isInitialRender.current = false;
}
}, []);
};
const App = () => {
const [count, setCount] = useState(0);
use初回レンダリング時のみ実行(() => {
// 最初のレンダリング時にのみ実行される副作用
console.log('useEffect が実行されました');
});
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>カウントを増やす</button>
</div>
);
};
export default App;
useEffect の代わりに useLayoutEffect を使用する
const App = () => {
const [count, setCount] = useState(0);
useLayoutEffect(() => {
// 最初のレンダリング時と、依存関係の値が更新されたタイミングで実行される副作用
console.log('useLayoutEffect が実行されました');
}, [count]);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>カウントを増やす</button>
</div>
);
};
export default App;
useEffect フックを最初のレンダリングで実行しない方法
useMemo Hook を使って、依存関係の値に基づいて計算される値をキャッシュすることができます。
const App = () => {
const [count, setCount] = useState(0);
const memoizedValue = useMemo(() => {
// 計算コストの高い処理
return someExpensiveCalculation(count);
}, [count]);
useEffect(() => {
// memoizeされた値が更新された時にのみ実行される副作用
console.log('useEffect が実行されました');
}, [memoizedValue]);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>カウントを増やす</button>
</div>
);
};
export default App;
const App = () => {
const [count, setCount] = useState(0);
const memoizedCallback = useCallback(() => {
// 副作用を実行する関数
console.log('useEffect が実行されました');
}, [count]);
useEffect(() => {
// memoizeされた関数が更新された時にのみ実行される副作用
memoizedCallback();
}, [memoizedCallback]);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>カウントを増やす</button>
</div>
);
};
export default App;
shouldComponentUpdate を使用する
クラスベースのコンポーネントを使用している場合は、shouldComponentUpdate メソッドをオーバーライドして、最初のレンダリング時にコンポーネントを更新しないようにすることができます。
class App extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
shouldComponentUpdate(nextProps, nextState) {
// 最初のレンダリング時は更新しない
return this.props.count !== nextProps.count || this.state.count !== nextState.count;
}
render() {
const { count } = this.state;
useEffect(() => {
// 最初のレンダリング時にのみ実行される副作用
console.log('useEffect が実行されました');
}, []);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => this.setState({ count: count + 1 })}>カウントを増やす</button>
</div>
);
}
}
export default App;
javascript reactjs react-hooks