| name | react-use-effect |
| description | Rules for useEffect usage in React including when to avoid it and when to extract it into custom hooks. Use when writing or reviewing React components that contain or might need useEffect. |
| user-invocable | false |
useEffectの使いどころを見極める
useEffectは外部システム(ブラウザAPI、ネットワーク、サードパーティライブラリ)との同期にのみ使います。
それ以外の用途では、より適切な代替手段がないか検討してください。
参考: You Might Not Need an Effect
useEffectを使わずに解決するパターン
レンダリング用のデータ変換は直接計算します
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(firstName + " " + lastName);
}, [firstName, lastName]);
const fullName = firstName + " " + lastName;
ユーザー操作の処理はイベントハンドラで行います
useEffect(() => {
if (product.isInCart) {
showNotification(`Added ${product.name} to cart!`);
}
}, [product]);
function handleBuyClick() {
addToCart(product);
showNotification(`Added ${product.name} to cart!`);
}
propsが変わったときの状態リセットにはkeyを使います
useEffect(() => {
setComment("");
}, [userId]);
<Profile userId={userId} key={userId} />;
高コストな計算のキャッシュにはuseMemoを使います
useEffect(() => {
setFilteredTodos(getFilteredTodos(todos, filter));
}, [todos, filter]);
const filteredTodos = useMemo(() => getFilteredTodos(todos, filter), [todos, filter]);
データ取得にはデータフェッチライブラリを使います
useEffect(() => {
let ignore = false;
fetchData(id).then((data) => {
if (!ignore) setData(data);
});
return () => {
ignore = true;
};
}, [id]);
const result = useSuspenseQuery({ queryKey: ["data", id], queryFn: () => fetchData(id) });
useEffectが適切なケース
- ブラウザAPIとの同期(
IntersectionObserver、ResizeObserverなど)
- サードパーティライブラリの初期化・破棄
- 外部接続の管理(WebSocketなど)
これらの場合でも、
より高抽象度なhooksやライブラリが使えないか検討してください。
useEffectを使う場合はカスタムフックに切り出す
コンポーネント本体にuseEffectを直接書くことは禁止です。
必ずカスタムフックに切り出し、コンポーネント側はそのフックを呼ぶだけにしてください。
カスタムフックには責務を表す名前をつけます。
useDocumentTitle, useWindowResize, useDeviceListSubscriptionなど。
フックの配置場所はプロジェクトの規約に従ってください。
典型的にはsrc/hooks/のような共有ディレクトリか、
そのコンポーネントに固有のものであれば同じディレクトリの別ファイルに置きます。