はじめに
「ウィンドウサイズを取得するフック、前のプロジェクトでも書いたな……」と思いながら、また同じようなuseWindowSizeを書いた経験はありませんか?
useLocalStorage、useDebounce、useToggle——Reactで開発していると、プロジェクトが変わるたびに似たようなカスタムフックを書き直しがちです。コピペで済ませても、微妙に挙動が違うバージョンがプロジェクトごとに散らばっていく。そんな「カスタムフックの車輪の再発明」を一気に解決してくれるのが、今回紹介するReact-Useです。
100個を超えるフックが1つのパッケージに詰まっており、GitHubスター数は44,000超。Reactフック集の定番として長く使われ続けているライブラリです。
React-Useとは
React-Useは、React用のカスタムフックを網羅的に集めたユーティリティライブラリです。TypeScriptで書かれており、センサー系からアニメーション、状態管理まで、日常の開発で「あったらいいな」と思うフックがほぼ揃っています。
2026年6月リリースのv17.6.1まで257回のリリースを重ねており、現在も活発にメンテナンスされています。ライセンスはUnlicense(パブリックドメイン)で、商用利用も安心です。
主な特徴
- 圧倒的な網羅性 - 100個以上のフックが6つのカテゴリ(Sensors / UI / Animations / Side-effects / Lifecycles / State)に整理されています
- TypeScript製で型安全 - コードベースの99.5%がTypeScriptで書かれており、型定義が最初から付属します
- ツリーシェイキング対応 - 使ったフックだけがバンドルに含まれるため、100個入りでもバンドルサイズを心配する必要はありません
インストール
各パッケージマネージャーでインストールできます。
# npm
npm i react-use
# yarn
yarn add react-use
# pnpm
pnpm add react-use
追加の設定は一切不要です。インストールしたらすぐにインポートして使えます。
基本的な使い方
まずは最もシンプルなuseToggleから見てみましょう。モーダルの開閉やアコーディオンなど、ブール値の切り替えはUIの定番処理です。
import { useToggle } from 'react-use';
function Modal() {
const [isOpen, toggle] = useToggle(false);
return (
<div>
<button onClick={toggle}>モーダルを{isOpen ? '閉じる' : '開く'}</button>
{isOpen && <div className="modal">モーダルの中身です</div>}
</div>
);
}
useStateで書くとsetIsOpen(prev => !prev)のようなコードが必要ですが、useToggleならtoggleを呼ぶだけです。引数に値を渡せば明示的なセットもできます。
次に、レスポンシブ対応でよく使うuseWindowSizeです。
import { useWindowSize } from 'react-use';
function ResponsiveInfo() {
const { width, height } = useWindowSize();
return (
<p>
現在のウィンドウサイズ: {width} x {height}
</p>
);
}
リサイズイベントの登録・解除やクリーンアップ処理をすべてライブラリが引き受けてくれるので、コンポーネント側は「値を受け取るだけ」で済みます。
実践的なユースケース
ここからは、実際のプロジェクトで役立つ組み合わせを見ていきましょう。
1. useLocalStorageでテーマ設定を永続化する
ダークモードの設定など、リロードしても保持したい状態はuseLocalStorageが便利です。JSONのシリアライズ・デシリアライズも自動で行ってくれます。
import { useLocalStorage } from 'react-use';
function ThemeSwitcher() {
const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('app-theme', 'light');
return (
<div data-theme={theme}>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
{theme === 'light' ? 'ダーク' : 'ライト'}モードに切り替え
</button>
</div>
);
}
2. useDebounceで検索入力を最適化する
入力のたびにAPIを叩くと無駄なリクエストが大量に発生します。useDebounceを使えば「入力が止まってから一定時間後に処理する」を数行で実現できます。
import { useState } from 'react';
import { useDebounce } from 'react-use';
function SearchBox() {
const [input, setInput] = useState('');
const [query, setQuery] = useState('');
useDebounce(
() => {
setQuery(input); // 入力が止まって500ms後に確定
},
500,
[input]
);
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="キーワードを入力"
/>
<p>検索クエリ: {query}</p>
</div>
);
}
3. useAsyncで非同期処理のローディング管理を任せる
データ取得時の「ローディング中・エラー・成功」の3状態管理は、自前で書くと意外と面倒です。useAsyncなら状態管理を丸ごと任せられます。
import { useAsync } from 'react-use';
function UserProfile({ userId }: { userId: string }) {
const state = useAsync(async () => {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error('取得に失敗しました');
return response.json();
}, [userId]);
if (state.loading) return <p>読み込み中...</p>;
if (state.error) return <p>エラー: {state.error.message}</p>;
return <p>ユーザー名: {state.value.name}</p>;
}
4. useCopyToClipboardでコピー機能を実装する
コードスニペットや招待リンクの「コピーボタン」も1フックで完結します。
import { useCopyToClipboard } from 'react-use';
function CopyButton({ text }: { text: string }) {
const [state, copyToClipboard] = useCopyToClipboard();
return (
<button onClick={() => copyToClipboard(text)}>
{state.value === text ? 'コピーしました!' : 'コピー'}
</button>
);
}
5. useMediaでCSSメディアクエリをJSから使う
「モバイルではこのコンポーネント自体を描画しない」といった、CSSだけでは対応しづらい分岐もuseMediaならすっきり書けます。
import { useMedia } from 'react-use';
function Navigation() {
const isWide = useMedia('(min-width: 768px)');
return isWide ? <DesktopNav /> : <MobileNav />;
}
まとめ
React-Useは、100個超のフックを収録した「カスタムフックの百科事典」とも言えるライブラリです。
useToggleやuseWindowSizeなど、書きがちなフックが最初から揃っている- TypeScript製で型定義も完備、ツリーシェイキング対応でバンドルサイズも安心
- 44,000超のスターと257回のリリース実績があり、今も活発にメンテナンスされている
「このフック、自分で書くべきか?」と迷ったら、まずReact-Useのドキュメントを検索してみてください。たいていの場合、テスト済みの実装がすでに存在します。カスタムフックの車輪の再発明をやめて、その時間をプロダクト本来の機能開発に使いましょう。
