ReactJS上級者必見!useMemoとuseEffect + useStateを使いこなしてパフォーマンスを極限まで高める
ReactJSにおける useMemo と useEffect + useState の比較
useMemo
useMemo は、計算結果をメモ化 するフックです。引数として渡された関数を最初のレンダリング時のみ実行 し、その結果をキャッシュします。その後、依存関係が変化しない限り、キャッシュされた結果を再利用します。
useMemoを使うべきケース
- 計算コストの高い処理を memoize することで、パフォーマンスを向上させたい場合
- 依存関係に基づいて値を計算する必要がある場合
- コンポーネントのレンダリングを最適化したい場合
useMemoの例
const expensiveCalculation = () => {
// 計算コストの高い処理
};
const memoizedValue = useMemo(expensiveCalculation, []);
// memoizedValue は最初のレンダリング時のみ計算され、その後はキャッシュされる
useEffect + useState
useEffect は、副作用を実行 するフックです。引数として渡された関数は、レンダリング後 または 依存関係が変化した タイミングで実行されます。
useState は、状態変数を管理 するフックです。引数として渡された初期値に基づいて状態変数を初期化し、その後の更新は setState
関数を使用して行います。
useEffect + useStateを使うべきケース
- DOM操作など、レンダリング後に実行する必要がある処理がある場合
- データの取得など、非同期処理を行う場合
- 状態変数を更新する必要がある場合
const [count, setCount] = useState(0);
useEffect(() => {
// DOM操作など、レンダリング後に実行する処理
}, []);
useEffect(() => {
// データ取得など、非同期処理
const fetchData = async () => {
// ...
};
fetchData();
}, []);
// `setCount` 関数を使用して状態変数を更新
useMemo と useEffect + useState は、それぞれ異なる役割を持つため、状況によって使い分けることが重要です。
- useEffect + useState は、副作用を実行したり、状態変数を管理するために使用します。
以下の表は、useMemo と useEffect + useState の主な違いをまとめたものです。
機能 | useMemo | useEffect + useState |
---|---|---|
主な役割 | 計算結果のメモ化 | 副作用の実行、状態変数の管理 |
実行タイミング | 最初のレンダリング時のみ | レンダリング後、または依存関係が変化したタイミング |
依存関係 | あり | あり |
パフォーマンス | 計算コストの高い処理を memoize することでパフォーマンスを向上できる | 場合によってはパフォーマンスの低下を引き起こす可能性がある |
状態変数の更新 | 不可 | 可 |
useMemo
const expensiveCalculation = (num) => {
// 計算コストの高い処理
for (let i = 0; i < 1000000; i++) {
num *= num;
}
return num;
};
const App = () => {
const [num, setNum] = useState(0);
const memoizedValue = useMemo(() => expensiveCalculation(num), [num]);
return (
<div>
<input type="number" value={num} onChange={(e) => setNum(e.target.value)} />
<p>計算結果: {memoizedValue}</p>
</div>
);
};
useEffect + useState
const fetchData = async () => {
// データ取得
const response = await fetch("https://api.example.com");
const data = await response.json();
return data;
};
const App = () => {
const [data, setData] = useState([]);
useEffect(() => {
fetchData().then((data) => setData(data));
}, []);
return (
<div>
{data.map((item) => (
<p key={item.id}>{item.name}</p>
))}
</div>
);
};
このコードでは、useEffect
と useState
を使って、https://api.example.com
からデータを取得し、表示しています。useEffect
は、コンポーネントがレンダリングされた後、fetchData
関数を呼び出し、データを取得します。取得したデータは、useState
で管理されている data
という状態変数に格納されます。
上記のサンプルコードは、useMemo と useEffect + useState の使い方を理解するのに役立ちます。それぞれのフックの役割と利点を理解し、状況に合わせて使い分けることが重要です。
useMemo と useEffect + useState の代替方法
- useRef : 値をレンダリング間で保持したい場合
- memo : コンポーネントを memoize する場合
- useReducer : 状態管理が複雑な場合
- custom hook : コードを再利用したい場合
useRef
useRef は、レンダリング間で値を保持するためのフックです。useRef
で作成されたオブジェクトは、レンダリングが更新されてもその値を保持します。
const ref = useRef(0);
const App = () => {
const [count, setCount] = useState(0);
useEffect(() => {
ref.current = count;
}, [count]);
return (
<div>
<p>カウント: {count}</p>
<p>前回の値: {ref.current}</p>
</div>
);
};
このコードでは、useRef
で ref
というオブジェクトを作成し、count
の値を保持しています。レンダリングが更新されても、ref.current
には前回の count
の値が保持されます。
memo
memo は、コンポーネントを memoize するための関数です。memo
でラップされたコンポーネントは、その props が変化しない限り、再レンダリングされません。
memo の例
const MyComponent = ({ prop1, prop2 }) => {
// 処理
};
const MemoizedComponent = memo(MyComponent);
const App = () => {
const [prop1, setProp1] = useState(0);
const [prop2, setProp2] = useState(0);
return (
<div>
<MemoizedComponent prop1={prop1} prop2={prop2} />
</div>
);
};
このコードでは、MyComponent
を memo
でラップして、MemoizedComponent
というコンポーネントを作成しています。prop1
と prop2
の値が変化しない限り、MemoizedComponent
は再レンダリングされません。
useReducer
useReducer は、状態管理が複雑な場合に役立つフックです。useReducer
は、状態の更新ロジックを reducer 関数として分離し、状態変数を更新するためのアクションを dispatch することで、状態管理を簡潔に記述できます。
const reducer = (state, action) => {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
};
const App = () => {
const [count, dispatch] = useReducer(reducer, 0);
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => dispatch({ type: "INCREMENT" })}>+</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>-</button>
</div>
);
};
このコードでは、useReducer
を使って、count
という状態変数を管理しています。reducer
関数は、状態の更新ロジックを記述しており、dispatch
関数を使ってアクションを dispatch することで、状態変数を更新できます。
custom hook
custom hook は、コードを再利用したい場合に役立ちます。useState
や useEffect
などのフックを組み合わせて、独自のフックを作成することで、コードを整理し、再利用性を高めることができます。
custom hook の例
const useCounter = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount((prevCount) => prevCount + 1);
};
const decrement = () => {
setCount((prevCount) => prevCount - 1);
};
return { count, increment, decrement };
};
const App = () => {
const { count, increment, decrement } = useCounter();
return (
<div>
<p
javascript reactjs typescript