React Hooksとは?関数コンポーネントで状態管理を実現する仕組み
React Hooksは2019年のReact 16.8でリリースされた機能で、関数コンポーネントでもクラスコンポーネントと同等の機能(状態管理・ライフサイクル等)を使えるようにする仕組みです。現在ではHooksを使った関数コンポーネントがReact開発の標準となっています。
useState:状態管理の基本
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: "", age: 0 });
const increment = () => setCount(prev => prev + 1);
const updateName = (name) => setUser(prev => ({ ...prev, name }));
return (
Count: {count}
updateName(e.target.value)} />
);
}
useEffect:副作用の管理
import { useState, useEffect } from "react";
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isMounted = true;
setLoading(true);
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => {
if (isMounted) {
setUser(data);
setLoading(false);
}
});
// クリーンアップ関数(アンマウント時に実行)
return () => { isMounted = false; };
}, [userId]); // userId が変化したら再実行
if (loading) return Loading...;
return {user?.name};
}
useContext:グローバルな状態共有
import { createContext, useContext, useState } from "react";
// テーマコンテキストの作成
const ThemeContext = createContext(null);
// プロバイダーコンポーネント
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = () =>
setTheme(prev => prev === "light" ? "dark" : "light");
return (
{children}
);
}
// コンシューマーコンポーネント
function ThemedButton() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
);
}
useMemo・useCallback:パフォーマンス最適化
import { useMemo, useCallback, memo } from "react";
// useMemo: 重い計算結果をメモ化
function ExpensiveComponent({ items, filter }) {
// filterが変化した時だけ再計算
const filteredItems = useMemo(() =>
items.filter(item => item.category === filter),
[items, filter]
);
// useCallback: コールバック関数をメモ化
const handleClick = useCallback((id) => {
console.log("Clicked:", id);
}, []);
return (
{filteredItems.map(item => (
))}
);
}
// memo: コンポーネントをメモ化(propsが変わらなければ再レンダリングしない)
const ListItem = memo(({ item, onClick }) => (
onClick(item.id)}>{item.name}
));
useReducer:複雑な状態管理
import { useReducer } from "react";
const initialState = {
count: 0,
loading: false,
error: null
};
function reducer(state, action) {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
case "RESET":
return initialState;
case "SET_LOADING":
return { ...state, loading: action.payload };
case "SET_ERROR":
return { ...state, error: action.payload, loading: false };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
Count: {state.count}
);
}
カスタムHooks:ロジックの再利用
// useLocalStorage: ローカルストレージとの同期
import { useState, useEffect } from "react";
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch {
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];
}
// useDebounce: 入力値のデバウンス
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// 使用例
function SearchBox() {
const [query, setQuery] = useState("");
const debouncedQuery = useDebounce(query, 300);
useEffect(() => {
if (debouncedQuery) {
// 300ms入力が止まったらAPIを叩く
fetchSearchResults(debouncedQuery);
}
}, [debouncedQuery]);
return setQuery(e.target.value)} />;
}
まとめ
React Hooksを使いこなすことでコードが大幅にシンプルになり、ロジックの再利用性も向上します。useState・useEffect・useContextの基本から、useMemo・useCallbackによるパフォーマンス最適化、カスタムHooksによる抽象化まで段階的に習得していきましょう。