React レッスン5
Hooks入門
Reactの強力なHookシステムを理解しよう
Hooksとは?
Hooksは、関数コンポーネントでReactの機能(状態管理、副作用処理など)を 利用するための仕組みです。React 16.8で導入され、現在のReact開発の中心的な機能です。
主要なHooksには以下があります:
useState— 状態管理useEffect— 副作用処理(API呼び出し、タイマーなど)useRef— DOM参照やミュータブルな値の保持useMemo— 計算結果のメモ化useCallback— 関数のメモ化useContext— コンテキスト(グローバル状態)の利用
Hooksのルール(重要)
Hooksを使う際には、2つの重要なルールがあります。違反するとバグの原因になります。
// ルール1: トップレベルでのみ呼び出す
// → ループ、条件分岐、ネストされた関数の中でHooksを呼んではいけない
function MyComponent() {
// OK: トップレベル
const [count, setCount] = useState(0);
const [name, setName] = useState("");
// NG: 条件分岐の中
// if (count > 0) {
// const [extra, setExtra] = useState(""); // エラー!
// }
// NG: ループの中
// for (let i = 0; i < 3; i++) {
// const [item, setItem] = useState(""); // エラー!
// }
return <div>{count}</div>;
}
// ルール2: React関数コンポーネントまたはカスタムHookの中でのみ呼び出す
// → 通常のJavaScript関数の中では使えない
// NG: 普通の関数
// function helper() {
// const [value, setValue] = useState(""); // エラー!
// }
// OK: コンポーネント
function MyComponent() {
const [value, setValue] = useState(""); // OK
return <p>{value}</p>;
}
// OK: カスタムHook(useで始まる関数)
function useMyHook() {
const [value, setValue] = useState(""); // OK
return [value, setValue];
}useRef
useRef は、 レンダリング間で値を保持するためのHookです。DOM要素への参照にもよく使われます。useRefの変更は再レンダリングを引き起こしません。
import { useRef, useState } from "react";
// DOM要素への参照
function FocusInput() {
const inputRef = useRef(null);
const handleClick = () => {
// DOM要素に直接アクセス
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} placeholder="ここにフォーカス" />
<button onClick={handleClick}>フォーカスする</button>
</div>
);
}
// レンダリング回数のカウント(再レンダリングなし)
function RenderCounter() {
const [count, setCount] = useState(0);
const renderCount = useRef(0);
// レンダーのたびに増えるが、再レンダリングは起きない
renderCount.current += 1;
return (
<div>
<p>カウント: {count}</p>
<p>レンダリング回数: {renderCount.current}</p>
<button onClick={() => setCount(c => c + 1)}>+1</button>
</div>
);
}
// 前回の値を記憶する
function PreviousValue() {
const [count, setCount] = useState(0);
const prevCountRef = useRef(0);
// 現在の値を保存(次のレンダリングで「前回の値」として使える)
const prevCount = prevCountRef.current;
prevCountRef.current = count;
return (
<div>
<p>現在: {count}、前回: {prevCount}</p>
<button onClick={() => setCount(c => c + 1)}>+1</button>
</div>
);
}useMemoとuseCallback
パフォーマンス最適化のためのHooksです。重い計算や関数の再作成を防ぎます。
import { useState, useMemo, useCallback } from "react";
function ExpensiveComponent({ items, filter }) {
// useMemo: 計算結果をメモ化(依存配列が変わるまで再計算しない)
const filteredItems = useMemo(() => {
console.log("フィルタリング実行...");
return items.filter(item =>
item.name.includes(filter)
);
}, [items, filter]); // items または filter が変わった時だけ再計算
// useCallback: 関数をメモ化(依存配列が変わるまで同じ関数を返す)
const handleClick = useCallback((id) => {
console.log("クリック:", id);
}, []); // 依存なし → 常に同じ関数
return (
<div>
<p>{filteredItems.length}件</p>
{filteredItems.map(item => (
<div key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</div>
))}
</div>
);
}
// 注意: useMemo/useCallbackは最適化のためのもの
// すべての値や関数に使う必要はありません
// パフォーマンスに問題がある場合にのみ検討しましょうカスタムHook
ロジックを再利用可能な関数にまとめたものがカスタムHookです。 名前は必ず use で始めます。
import { useState, useEffect } from "react";
// カスタムHook: カウンター機能
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(c => c + 1);
const decrement = () => setCount(c => c - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
}
// カスタムHook: ローカルストレージと同期
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const saved = localStorage.getItem(key);
return saved ? JSON.parse(saved) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// カスタムHook: ウィンドウサイズの取得
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
setSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return size;
}
// 使い方
function App() {
const { count, increment, decrement, reset } = useCounter(0);
const [name, setName] = useLocalStorage("userName", "");
const { width, height } = useWindowSize();
return (
<div>
<p>カウント: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>リセット</button>
<input value={name} onChange={e => setName(e.target.value)} />
<p>画面サイズ: {width} x {height}</p>
</div>
);
}まとめ
- Hooksは関数コンポーネントでReactの機能を使うための仕組み
- Hooksはトップレベルでのみ呼び出す(条件分岐やループの中はNG)
useRefはDOM参照やレンダリング間の値保持に使うuseMemo/useCallbackはパフォーマンス最適化用- カスタムHookでロジックを再利用可能にする