React Hooks 完全ガイド¶
React Hooksを基礎から実践まで完全マスターするための日本語ガイド CDNで実行可能なサンプルコード付き
目次¶
- React Hooksとは
- CDNでReactを使う方法
- useState - 状態管理
- useEffect - 副作用処理
- useContext - グローバル状態共有
- useMemo - 計算結果のメモ化
- useCallback - 関数のメモ化
- useRef - DOM参照と永続値
- useReducer - 複雑な状態管理
- Custom Hooks - カスタムフック
- Hooks一覧表
- ベストプラクティス
React Hooksとは¶
React Hooks(フックス) は、関数コンポーネントでReactの機能を使うための「魔法の関数」です。
Hooksが解決する問題¶
- クラスコンポーネントの複雑さを排除:
thisの煩わしさから解放 - ロジックの再利用: 関数として切り出し可能
- コードの可読性向上: シンプルで理解しやすい
Hooksの基本ルール¶
- トップレベルでのみ呼び出す: ループや条件分岐の中で使わない
- 関数コンポーネント内で使う: 通常の関数では使えない
- 名前は
useで始める: カスタムフックを作るときの約束
CDNでReactを使う方法¶
Node.jsやビルドツールがなくても、CDNを読み込めばReactを動かせます。 以下の3行をHTMLに書くだけでOK。
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
重要ポイント:
- HTML内でReactコードを書くときは <script type="text/babel"> を使うとJSXが動きます
- これはCSR(Client Side Rendering)です
- サーバーサイドレンダリング(SSR)は動きませんが、練習・理解には最適
useState - 状態管理¶
概念¶
useState は、Reactが値を覚えてくれる(状態管理)Hookです。
| Hook | 役割 | たとえ |
|---|---|---|
| useState | Reactが変数を覚えてくれる | 「覚えておくメモ帳」 |
使うタイミング¶
- コンポーネント内で値を保持したいとき
- ユーザーの入力や操作で値が変わるとき
- 値の変更に応じて画面を再レンダリングしたいとき
CDN実行サンプル¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>useState基本例</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function App() {
const [count, setCount] = React.useState(0);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>増やす</button>
<button onClick={() => setCount(count - 1)}>減らす</button>
<button onClick={() => setCount(0)}>リセット</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
ベストプラクティス¶
// ✅ 良い例: 前の状態を使う場合は関数形式
setCount((prevCount) => prevCount + 1);
// ❌ 悪い例: 連続で更新すると意図しない結果に
setCount(count + 1);
setCount(count + 1); // これは2回加算されない
useEffect - 副作用処理¶
概念¶
useEffect は、状態が変わった後に実行される(副作用)Hookです。
| Hook | 役割 | たとえ |
|---|---|---|
| useEffect | 副作用(API呼び出しやDOM操作)を行う | 「何かが変わったら動くスイッチ」 |
使うタイミング¶
- コンポーネントのマウント時に処理を実行したいとき
- 特定の値が変更されたときに処理を実行したいとき
- データフェッチ、購読の設定、タイマーなど
CDN実行サンプル¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>useState & useEffect</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function App() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
console.log("カウントが変わった:", count);
document.title = `カウント: ${count}`;
}, [count]);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>増やす</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
依存配列のパターン¶
// パターン1: マウント時のみ実行
React.useEffect(() => {
console.log("初回レンダリング時のみ");
}, []);
// パターン2: 特定の値が変わったときのみ
React.useEffect(() => {
console.log("countが変わった");
}, [count]);
// パターン3: 毎回実行(非推奨)
React.useEffect(() => {
console.log("毎回実行される");
});
クリーンアップ関数¶
React.useEffect(() => {
const timer = setInterval(() => {
console.log("1秒経過");
}, 1000);
// クリーンアップ: コンポーネントがアンマウントされるときに実行
return () => {
clearInterval(timer);
};
}, []);
ベストプラクティス¶
// ✅ 良い例: 依存配列を正しく設定
React.useEffect(() => {
fetchData(userId);
}, [userId]);
// ❌ 悪い例: 依存配列を空にすると無限ループの危険
React.useEffect(() => {
setCount(count + 1); // これは無限ループになる
}, [count]);
useContext - グローバル状態共有¶
概念¶
useContext は、親から子に毎回propsで渡さなくても済む、アプリ全体で共有できる「共通データの保管庫」です。
| Hook | 役割 | たとえ |
|---|---|---|
| useContext | コンテキストの値を取り出す | 「共有冷蔵庫からジュース取る」 |
使うタイミング¶
- テーマ(ダークモード/ライトモード)の共有
- ログインユーザー情報の共有
- 多階層にわたるpropsのバケツリレーを避けたいとき
CDN実行サンプル¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>useContext</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const ThemeContext = React.createContext("light");
function Child() {
const theme = React.useContext(ThemeContext);
return <p>現在のテーマ: {theme}</p>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<h1>Contextの例</h1>
<Child />
</ThemeContext.Provider>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
より実践的な例¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>useContext - テーマ切り替え</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const ThemeContext = React.createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = React.useState("light");
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemedComponent() {
const { theme, toggleTheme } = React.useContext(ThemeContext);
const style = {
backgroundColor: theme === "light" ? "#fff" : "#333",
color: theme === "light" ? "#000" : "#fff",
padding: "20px",
};
return (
<div style={style}>
<h1>現在のテーマ: {theme}</h1>
<button onClick={toggleTheme}>テーマを切り替え</button>
</div>
);
}
function App() {
return (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
ベストプラクティス¶
// ✅ 良い例: Contextをカスタムフックでラップ
function useTheme() {
const context = React.useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
}
// 使用時
const { theme, toggleTheme } = useTheme();
useMemo - 計算結果のメモ化¶
概念¶
useMemo は、計算結果をキャッシュする(重い処理向け)Hookです。
| Hook | 役割 | たとえ |
|---|---|---|
| useMemo | 計算結果を覚えて再利用する | 「前回の答えをメモしておく」 |
使うタイミング¶
- 計算コストが高い処理の結果を保存したいとき
- 参照の同一性を保ちたいとき(オブジェクトや配列)
- 不要な再計算を避けたいとき
CDN実行サンプル¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>useMemo</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function App() {
const [count, setCount] = React.useState(0);
const [input, setInput] = React.useState("");
// countが変わった時のみ再計算される
const double = React.useMemo(() => {
console.log("再計算中…");
return count * 2;
}, [count]);
return (
<div>
<h1>useMemoの例</h1>
<p>count: {count}</p>
<p>double: {double}</p>
<button onClick={() => setCount(count + 1)}>増やす</button>
<hr />
<p>inputを変更してもdoubleは再計算されない</p>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="ここに入力"
/>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
ベストプラクティス¶
// ✅ 良い例: 重い計算をメモ化
const expensiveValue = React.useMemo(() => {
return items.filter(item => item.price > 1000)
.map(item => item.price * 1.1);
}, [items]);
// ❌ 悪い例: 単純な計算には不要(むしろオーバーヘッド)
const simple = React.useMemo(() => count + 1, [count]);
useCallback - 関数のメモ化¶
概念¶
useCallback は、関数をキャッシュする(再レンダリング防止)Hookです。
| Hook | 役割 | たとえ |
|---|---|---|
| useCallback | 関数をメモ化する | 「同じ関数を毎回作らずに再利用」 |
使うタイミング¶
- 子コンポーネントに関数をpropsとして渡すとき
- useEffectの依存配列に関数を入れるとき
- 無駄な再レンダリングを防ぎたいとき
CDN実行サンプル¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>useMemo & useCallback</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function App() {
const [count, setCount] = React.useState(0);
const double = React.useMemo(() => {
console.log("再計算中…");
return count * 2;
}, [count]);
const handleClick = React.useCallback(() => {
setCount((c) => c + 1);
}, []);
return (
<div>
<h1>useMemo/useCallbackの例</h1>
<p>count: {count}</p>
<p>double: {double}</p>
<button onClick={handleClick}>増やす</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
ベストプラクティス¶
// ✅ 良い例: 子コンポーネントに渡す関数をメモ化
const handleClick = React.useCallback(() => {
doSomething(id);
}, [id]);
return <ChildComponent onClick={handleClick} />;
// ❌ 悪い例: インライン関数は毎回新しく作られる
return <ChildComponent onClick={() => doSomething(id)} />;
useRef - DOM参照と永続値¶
概念¶
useRef は、DOMや変数を直接参照するHookです。
| Hook | 役割 | たとえ |
|---|---|---|
| useRef | DOMや変数を直接参照 | 「メモをポケットに入れておく」 |
使うタイミング¶
- DOM要素に直接アクセスしたいとき
- 再レンダリングをトリガーせずに値を保持したいとき
- 前回の値を覚えておきたいとき
CDN実行サンプル¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>useRef</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function App() {
const inputRef = React.useRef(null);
const countRef = React.useRef(0);
const focusInput = () => {
inputRef.current.focus();
};
const incrementRef = () => {
countRef.current += 1;
console.log("Ref count:", countRef.current);
// 注意: この変更は再レンダリングをトリガーしない
};
return (
<div>
<h1>useRefの例</h1>
<input ref={inputRef} type="text" placeholder="テキスト入力" />
<button onClick={focusInput}>インプットにフォーカス</button>
<hr />
<button onClick={incrementRef}>Refカウント増加(再レンダリングなし)</button>
<p>コンソールを確認してください</p>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
ベストプラクティス¶
// ✅ 良い例: DOM操作
const inputRef = React.useRef(null);
inputRef.current.focus();
// ✅ 良い例: 前回の値を保持
const prevCountRef = React.useRef();
React.useEffect(() => {
prevCountRef.current = count;
}, [count]);
// ❌ 悪い例: レンダリング中にrefを変更しない
function Component() {
const ref = React.useRef(0);
ref.current += 1; // これはNG
return <div>{ref.current}</div>;
}
useReducer - 複雑な状態管理¶
概念¶
useReducer は、状態管理をもう少し複雑にやるHookです。
| Hook | 役割 | たとえ |
|---|---|---|
| useReducer | 状態管理をもう少し複雑にやる | 「司令官が指示を出して部下が状態を変える」 |
使うタイミング¶
- 複数の関連する状態を管理するとき
- 次の状態が前の状態に依存するとき
- 状態の更新ロジックが複雑なとき
CDN実行サンプル¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>useReducer</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return { count: 0 };
default:
throw new Error("Unknown action type");
}
}
function App() {
const [state, dispatch] = React.useReducer(reducer, { count: 0 });
return (
<div>
<h1>useReducerの例</h1>
<p>カウント: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>増やす</button>
<button onClick={() => dispatch({ type: "decrement" })}>減らす</button>
<button onClick={() => dispatch({ type: "reset" })}>リセット</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
ベストプラクティス¶
// ✅ 良い例: アクションタイプを定数で定義
const ACTIONS = {
INCREMENT: "increment",
DECREMENT: "decrement",
RESET: "reset",
};
dispatch({ type: ACTIONS.INCREMENT });
// ✅ 良い例: payloadを使ってデータを渡す
dispatch({ type: "addTodo", payload: { text: "新しいタスク" } });
function reducer(state, action) {
switch (action.type) {
case "addTodo":
return {
todos: [...state.todos, { id: Date.now(), text: action.payload.text }],
};
default:
return state;
}
}
Custom Hooks - カスタムフック¶
概念¶
カスタムフック は、既存のHooksを組み合わせて「再利用できる関数」を自作できる仕組みです。
| Hook | 役割 | たとえ |
|---|---|---|
| カスタムフック | これらを組み合わせて自作したフック | 「自分用の便利ツール」 |
使うタイミング¶
- 複数のコンポーネントで同じロジックを使いたいとき
- 状態管理のロジックを分離したいとき
- コンポーネントをシンプルに保ちたいとき
命名規則¶
- 必ず
useで始める: これはReactの約束事 - camelCase:
useFetch,useTimer,useLocalStorage
CDN実行サンプル1: useWaterStatus¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>カスタムフック</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function useWaterStatus() {
const [thirst, setThirst] = React.useState(true);
const drink = () => setThirst(false);
const dry = () => setThirst(true);
return { thirst, drink, dry };
}
function App() {
const { thirst, drink, dry } = useWaterStatus();
return (
<div>
<h1>{thirst ? "のどが渇いた💦" : "満たされた💧"}</h1>
<button onClick={drink}>水を飲む</button>
<button onClick={dry}>乾く</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
CDN実行サンプル2: カスタムフック + useMemo¶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>カスタムフック + useMemo</title>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function useWaterStatus() {
const [thirst, setThirst] = React.useState(true);
return {
thirst,
drink: () => setThirst(false),
dry: () => setThirst(true),
};
}
function App() {
const { thirst, drink, dry } = useWaterStatus();
const message = React.useMemo(() => {
return thirst ? "のどが渇いた💦" : "満たされた💧";
}, [thirst]);
return (
<div>
<h1>{message}</h1>
<button onClick={dry}>乾く</button>
<button onClick={drink}>水を飲む</button>
</div>
);
}
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
</script>
</body>
</html>
実践的なカスタムフック例¶
useToggle¶
function useToggle(initialValue = false) {
const [value, setValue] = React.useState(initialValue);
const toggle = React.useCallback(() => setValue((v) => !v), []);
return [value, toggle];
}
// 使用例
function App() {
const [isOpen, toggleOpen] = useToggle(false);
return (
<div>
<button onClick={toggleOpen}>
{isOpen ? "閉じる" : "開く"}
</button>
{isOpen && <div>コンテンツが表示されています</div>}
</div>
);
}
useLocalStorage¶
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = React.useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore =
value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
// 使用例
function App() {
const [name, setName] = useLocalStorage("name", "");
return (
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="名前を入力"
/>
);
}
useFetch¶
function useFetch(url) {
const [data, setData] = React.useState(null);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(null);
React.useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const json = await response.json();
setData(json);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// 使用例
function App() {
const { data, loading, error } = useFetch(
"https://jsonplaceholder.typicode.com/posts/1"
);
if (loading) return <div>読み込み中...</div>;
if (error) return <div>エラー: {error.message}</div>;
return <div>{data.title}</div>;
}
ベストプラクティス¶
// ✅ 良い例: ロジックを分離して再利用可能に
function useAuth() {
const [user, setUser] = React.useState(null);
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
// 認証状態を確認
const unsubscribe = auth.onAuthStateChanged((user) => {
setUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
return { user, loading };
}
// ❌ 悪い例: useで始まらない名前
function getUser() { // これはカスタムフックではない
const [user, setUser] = React.useState(null);
return user;
}
Hooks一覧表¶
基本Hooks¶
| Hook | 説明 | たとえ |
|---|---|---|
| useState | 状態(変数)をReactに覚えさせる | 「覚えておくメモ帳」 |
| useEffect | 副作用(API呼び出しやDOM操作)を行う | 「何かが変わったら動くスイッチ」 |
| useContext | コンテキストの値を取り出す | 「共有冷蔵庫からジュース取る」 |
パフォーマンス最適化Hooks¶
| Hook | 説明 | たとえ |
|---|---|---|
| useMemo | 計算結果を覚えて再利用する | 「前回の答えをメモしておく」 |
| useCallback | 関数をメモ化する | 「同じ関数を毎回作らずに再利用」 |
特殊用途Hooks¶
| Hook | 説明 | たとえ |
|---|---|---|
| useRef | DOMや変数を直接参照 | 「メモをポケットに入れておく」 |
| useReducer | 状態管理をもう少し複雑にやる | 「司令官が指示を出して部下が状態を変える」 |
カスタムHooks¶
| Hook | 説明 | たとえ |
|---|---|---|
| カスタムフック | これらを組み合わせて自作したフック | 「自分用の便利ツール」 |
ベストプラクティス¶
1. Hooksの順序を守る¶
// ✅ 良い例: トップレベルで使う
function Component() {
const [count, setCount] = React.useState(0);
const [name, setName] = React.useState("");
return <div>{count}</div>;
}
// ❌ 悪い例: 条件分岐の中で使う
function Component() {
if (condition) {
const [count, setCount] = React.useState(0); // NG
}
return <div>Hello</div>;
}
2. useEffectの依存配列を正確に¶
// ✅ 良い例: 必要な依存をすべて含める
React.useEffect(() => {
fetchData(userId);
}, [userId]);
// ❌ 悪い例: 依存配列が不足
React.useEffect(() => {
fetchData(userId);
}, []); // userIdが変わっても実行されない
3. カスタムフックで再利用性を高める¶
// ✅ 良い例: ロジックを分離
function useWindowSize() {
const [size, setSize] = React.useState({
width: window.innerWidth,
height: window.innerHeight,
});
React.useEffect(() => {
const handleResize = () => {
setSize({
width: window.innerWidth,
height: window.innerHeight,
});
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return size;
}
4. useMemo/useCallbackは必要な時だけ¶
// ✅ 良い例: 重い計算をメモ化
const filteredList = React.useMemo(() => {
return items.filter(item => item.price > 1000);
}, [items]);
// ❌ 悪い例: 単純な計算にはオーバーヘッド
const total = React.useMemo(() => a + b, [a, b]); // 不要
5. useRefは再レンダリングが不要な値に¶
// ✅ 良い例: DOM参照や前回の値
const inputRef = React.useRef(null);
const prevCountRef = React.useRef();
// ❌ 悪い例: 画面に表示する値はuseState
const countRef = React.useRef(0); // 画面に表示するならuseStateを使うべき
学習の順序¶
- useState → 基本中の基本
- useEffect → 副作用を理解する
- useContext → グローバル状態を学ぶ
- useMemo / useCallback → 最適化を学ぶ
- useRef → DOM操作を学ぶ
- useReducer → 複雑な状態管理を学ぶ
- Custom Hooks → 再利用可能なロジックを作る
よくある問題と解決策¶
| 問題 | 原因 | 解決策 |
|---|---|---|
| useEffectがループする | 依存配列が間違っている | [依存するstateだけ] にする |
| 再レンダリングが多い | propsや関数を都度生成している | useMemo / useCallback で固定 |
| 状態が更新されない | 非同期処理のタイミング問題 | useEffectで適切に処理する |
| カスタムフックが動かない | 命名がuseで始まっていない |
必ずuseで始める |
フォルダ構成・命名ルール¶
推奨フォルダ構成¶
src/
┣ components/ ← UIの部品(Button.jsx, Card.jsx)
┣ hooks/ ← カスタムフック(useFetch.js, useTimer.js)
┣ contexts/ ← Context管理(ThemeContext.js)
┣ pages/ ← 各ページ(Home.jsx, About.jsx)
┣ App.jsx ← ルートコンポーネント
┗ index.js ← ReactDOM.render()する入口
命名ルール¶
| 種類 | 命名ルール | 例 |
|---|---|---|
| コンポーネント | PascalCase | UserCard |
| Hook | camelCase + "use" | useFetch, useTimer |
| Context | PascalCase + "Context" | ThemeContext |
| CSS | .module.css(Next.js推奨) | Button.module.css |
まとめ¶
React Hooksは、関数コンポーネントでReactの強力な機能を使うための仕組みです。
重要ポイント¶
- useState: 状態を管理する基本のHook
- useEffect: 副作用を扱う重要なHook
- useContext: グローバルな状態共有
- useMemo/useCallback: パフォーマンス最適化
- useRef: DOM操作や永続値の保持
- useReducer: 複雑な状態管理
- Custom Hooks: 再利用可能なロジックの作成
学習のコツ¶
- CDNで小さい実験をする: 環境構築で迷わない
- コンソールにconsole.log()を入れて動きを観察: 動きを理解する
- 毎日1フックずつ覚える: useState → useEffect → useContext → useMemo
- コードに日本語コメントを書く: 理解を深める
- 動かして・壊して・直して覚える: 実践が最短
Reactは「動かして・壊して・直して」覚えるのが最短です。
このガイドのサンプルコードをコピーして、ブラウザで実行してみてください。 理解が深まったら、自分なりのカスタムフックを作ってみましょう。