💡はじめに
Reactでは「Hooks」を使用することで、状態管理やライフサイクル処理などを関数コンポーネント内で簡単に実装できます。
Hooksを理解することで、Reactの動きやコンポーネントの仕組みを理解しやすくなります。
この記事では、Reactでよく使用されるHooksについて、簡単なサンプルコードを交えながら紹介していきます。
できるだけシンプルにまとめているので、React学習中の方の参考になれば幸いです。
✈️関連記事はこちら
React Hooks入門①
React Hooks入門②
👍こんな人におすすめ
・最近Reactを勉強し始めた
・Reactをもう少し理解したい
・使用経験のないHooksを理解したい
・さくっと学びたい
🚩React Hooks
目次
15.useDebugValue
16.useOptimistic
17.useActionState
18.useFormStatus
19.useInsertionEffect
20.use
15.useDebugValue
useDebugValueは、Custom Hookの状態をReact DevToolsへ表示するためのHookです。
通常の画面上では変化ありませんが、Hookの状態を分かりやすく確認できるようになります。
主にcustomHook開発時やデバッグ用途で利用されます。
import './App.css';
import useStatus from './useStatus';
function App() {
const {
isOnline,
toggleStatus
} = useStatus();
return (
<div>
<h1>useDebugValue</h1>
<p>
ステータス:
{isOnline ? 'Online' : 'Offline'}
</p>
<button onClick={toggleStatus}>
切り替え
</button>
</div>
);
}
export default App;
import {
useDebugValue,
useState
} from 'react';
const useStatus = () => {
const [isOnline, setIsOnline] = useState(true);
// DevToolsへ表示
useDebugValue(
isOnline ? 'Online' : 'Offline'
);
const toggleStatus = () => {
setIsOnline(!isOnline);
};
return {
isOnline,
toggleStatus
};
};
export default useStatus;
useDebugValue()は以下のように記述します。
useDebugValue(表示したい値);
今回の場合は、React DevToolsへ現在の状態を表示しています。
useDebugValue(
isOnline ? 'Online' : 'Offline'
);
画面上では特に変化ありませんが、React DevToolsを確認するとcustomHookの状態を確認できます。
例えば以下のような場面で利用されます。
・customHookのデバッグ
・状態確認
・Hook開発
・DevTools表示改善
主に開発時やデバッグ用途で利用されるHookです。
16.useOptimistic
useOptimisticは、非同期処理完了前に画面を先に更新できるHookです。
API通信などでは、レスポンスを待つまで画面更新が遅れる場合があります。
useOptimisticを使用することで、処理成功を前提として先にUIを更新できます。
API通信が失敗した場合は、エラーメッセージを表示したり元の状態に戻したりする処理が必要です。
import { useOptimistic, useState } from 'react';
import './App.css';
function App() {
const [messages, setMessages] = useState([]);
// 楽観的更新
const [optimisticMessages, addOptimisticMessage]
= useOptimistic(
messages,
(state, newMessage) => [
...state,
newMessage
]
);
const handleSubmit = async () => {
const newMessage = 'メッセージ';
addOptimisticMessage(newMessage);
try {
await new Promise((resolve) =>
setTimeout(resolve, 1000)
);
setMessages((prev) => [
...prev,
newMessage
]);
} catch (error) {
console.error(error);
// エラー表示やロールバック処理を行う
}
};
return (
<div>
<h1>useOptimistic</h1>
<button onClick={handleSubmit}>
追加
</button>
<ul>
{optimisticMessages.map((message, index) => (
<li key={index}>
{message}
</li>
))}
</ul>
</div>
);
}
export default App;
useOptimisticは以下のように記述します。
const [
optimisticState,
addOptimistic
] = useOptimistic(
state,
updateFunction
);
| 名前 | 内容 |
|---|---|
| optimisticState | 一時的な状態 |
| addOptimistic | 楽観的更新関数 |
| state | 元の状態 |
| updateFunction | 更新処理 |
今回の場合は、API通信完了前にメッセージを画面へ表示しています。
addOptimisticMessage(newMessage);
その後、非同期処理完了後に実際の状態を更新しています。
setMessages((prev) => [
...prev,
newMessage
]);
※ 実務では、リストのkeyにはindexではなく、データが持つidなど一意な値を使うのが望ましいです。
{optimisticMessages.map((message, index) => (
<li key={index}>
{message}
</li>
))}
これにより、ユーザーは待ち時間を感じにくくなります。
例えば以下のような場面で利用されます。
・チャット送信
・コメント投稿
・いいね機能
・お気に入り登録
API通信の完了を待たずに画面を更新したい場合に利用されるHookです。
17.useActionState
useActionStateは、フォーム送信などのアクション結果を管理できるHookです。
フォーム送信時の状態管理やエラーメッセージ表示を簡単に実装できます。
React19で追加されたHookです。
import { useActionState } from 'react';
import './App.css';
// action
const submitForm = async (prevState, formData) => {
const name = formData.get('name');
// 入力チェック
if (!name) {
return {
success: false,
message: '名前を入力してください'
};
}
// API通信を想定
await new Promise((resolve) =>
setTimeout(resolve, 1000)
);
return {
success: true,
message: `${name} を登録しました`
};
};
function App() {
const [state, formAction, isPending]
= useActionState(
submitForm,
{
success: false,
message: ''
}
);
return (
<div>
<h1>useActionState</h1>
<form action={formAction}>
<input
type="text"
name="name"
placeholder="名前"
/>
<button type="submit">
送信
</button>
</form>
{isPending && <p>送信中...</p>}
<p>{state.message}</p>
</div>
);
}
export default App;
useActionStateは以下のように記述します。
const [
state,
formAction,
isPending
] = useActionState(
action,
initialState
);
| 名前 | 内容 |
|---|---|
| state | 現在の状態 |
| formAction | form用action |
| isPending | 処理中状態 |
| action | 実行処理 |
| initialState | 初期値 |
今回の場合は、フォーム送信時にsubmitForm()が実行されます。
<form action={formAction}>
入力値はformDataから取得できます。
const name = formData.get('name');
送信中はisPendingがtrueになるため、ローディング表示も可能です。
{isPending && <p>送信中...</p>}
例えば以下のような場面で利用されます。
・フォーム送信
・ログイン処理
・バリデーション
・非同期アクション管理
フォーム関連処理をシンプルに管理したい場合に利用されるHookです。
18.useFormStatus
useFormStatusは、フォーム送信中の状態を取得できるHookです。
React19で追加されたHookで、フォーム送信中のローディング表示やボタンの制御を簡単に実装できます。
通常はuseActionStateと組み合わせて利用します。
import { useActionState } from 'react';
import SubmitButton from './SubmitButton';
import './App.css';
const submitForm = async (prevState, formData) => {
await new Promise((resolve) =>
setTimeout(resolve, 2000)
);
return {
message: '送信完了'
};
};
function App() {
const [state, formAction] = useActionState(
submitForm,
{
message: ''
}
);
return (
<div>
<h1>useFormStatus</h1>
<form action={formAction}>
<input
type="text"
name="name"
placeholder="名前"
/>
<SubmitButton />
</form>
<p>{state.message}</p>
</div>
);
}
export default App;
import { useFormStatus } from 'react-dom';
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button
type="submit"
disabled={pending}
>
{pending ? '送信中...' : '送信'}
</button>
);
}
export default SubmitButton;
useFormStatus()は以下のように記述します。
const { pending } = useFormStatus();
pending・・・フォーム送信中かどうか
今回の場合は、フォーム送信中にボタンを無効化しています。
<button
type="submit"
disabled={pending}
>
また、送信中はボタンの表示を変更しています。
{pending ? '送信中...' : '送信'}
これにより、ユーザーが連続で送信ボタンを押してしまうことを防げます。
例えば以下のような場面で利用されます。
・お問い合わせフォーム
・ログイン画面
・会員登録画面
・データ登録処理
フォーム送信中の状態管理を簡単に行いたい場合に利用されるHookです。
19.useInsertionEffect
useInsertionEffectは、useLayoutEffectより前に実行されるHookで、主にCSS-in-JSライブラリがスタイルを挿入するために利用されます。
通常のアプリケーション開発で直接使うことはほとんどありません。
import {
useInsertionEffect,
useState
} from 'react';
import './App.css';
function App() {
const [count, setCount] = useState(0);
useInsertionEffect(() => {
console.log('useInsertionEffect 実行');
}, [count]);
return (
<div>
<h1>useInsertionEffect</h1>
<p>count:{count}</p>
<button
onClick={() => setCount(count + 1)}
>
カウントアップ
</button>
</div>
);
}
export default App;
このサンプルでは動作確認のためにconsole.logを出していますが、実際にはCSS-in-JSライブラリなどがスタイルを挿入する用途で利用するHookです。
通常のアプリ開発ではほとんど使いません。
useInsertionEffectは以下のように記述します。
useInsertionEffect(() => {
実行したい処理
}, [監視する値]);
今回の場合は、countが変更されるたびに処理が実行されます。
useInsertionEffect(() => {
console.log('useInsertionEffect 実行');
}, [count]);
useEffectやuseLayoutEffectとの実行タイミングの違いは以下の通りです。
| Hook | 主な実行タイミング・用途 |
|---|---|
| useInsertionEffect | useLayoutEffectより前。主にCSS-in-JSのスタイル挿入用 |
| useLayoutEffect | DOM更新後、ブラウザ描画前に同期的に実行 |
| useEffect | ブラウザ描画後に実行されることが多い |
例えば以下のような場面で利用されます。
・CSS-in-JSライブラリ
・スタイルの動的挿入
・ライブラリ開発
useInsertionEffectは、レイアウト計算が行われる前にスタイルを挿入するための特殊なHookです。
一般的なReactアプリではほとんど利用されませんが、Reactが提供しているHookの1つです。
20.use
useは名前がuseから始まりますが、useStateやuseEffectのような通常のHookとは少し性質が異なります。
通常のHooksは条件分岐やループの中で呼び出せませんが、useは条件分岐やループの中で呼び出すことができます。
import { Suspense, use } from 'react';
import './App.css';
// API通信を想定
const fetchUser = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: 'React User'
});
}, 2000);
});
};
const userPromise = fetchUser();
function UserInfo() {
const user = use(userPromise);
return (
<p>ユーザー名:{user.name}</p>
);
}
function App() {
return (
<div>
<h1>use</h1>
<Suspense fallback={<p>読み込み中...</p>}>
<UserInfo />
</Suspense>
</div>
);
}
export default App;
useでPromiseを読み込む場合、Promiseが完了するまでコンポーネントはSuspenseによって待機状態になります。
そのため、Suspenseのfallbackを用意する必要があります。
use()は以下のように記述します。
const data = use(promise);
Promiseの処理が完了するまで待機し、完了後に値を取得できます。
const user = use(userPromise);
今回の場合は、API通信を想定したPromiseからユーザー情報を取得しています。
従来の実装では以下のように記述することが一般的でした。
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser().then((data) => {
setUser(data);
});
}, []);
use()を使用することで、非同期処理をよりシンプルに記述できます。
例えば以下のような場面で利用されます。
・API通信
・非同期データ取得
・Server Components
・Contextの取得
React19で追加された新しいHookで、今後利用機会が増えていくHookの1つです。
✈️関連記事
React Hooks入門①