React19 use Hookについて
use Hookとは
use hook
は、Reactのバージョン19に導入される新しいhookで、コンテキストとプロミスを使う時に便利です。
ReactではuseState
やuseEffect
のようなHookをif文の内部で使用することができませんでしたが、(ReactのHookルールに違反するため)use hook
はループやifのような条件文の中で呼び出すことができます。
サーバーコンポーネントからデータを取得し、クライアントコンポーネントに渡すことができるRSC(React Server Component)が登場しました。ここでuse hook
を使用すると、プロミスとコンテキストから値を取得できます。
RSCとは
RSCは、React Server Componentの略で、サーバーでレンダリングされるコンポーネントを意味します。サーバーコンポーネントはasync関数として宣言され、内部でawaitを使用して非同期データを取得し、それをレンダリングすることが可能です。非同期コンポーネントになります。
- RSCでは、useStateやuseEffectのようにクライアントで使用されるフックは使用できません。(シリアライズが必要なため)
- RSCでは、onClickやonFocusのようなイベントハンドラーは使用できません。(シリアライズが必要なため)
RSCのレンダリングが完了するまで、クライアントではReactのSuspenseを使用してRSCの位置に別のコンポーネントを表示することが可能です。 - RSCで使用されるパッケージは全てサーバーでimportされ、サーバーでのみ使用されるため、JSバンドルとしてクライアントに伝達されません。
use hookを使用してプロミスを処理する
// server component
import { fetchproductData } from './api.js';
import { ProductCard } from './ProductCard.jsx';
const App = () => {
const productPromise = fetchproductData();
return <ProductCard productPromise={productPromise} />;
};
export default App;
上記のコードを見ると、サーバーコンポーネントからproductData
を取得し、クライアントコンポーネントに渡しています。これで、クライアントコンポーネントではuse hook
を使用してこのプロミスを利用できます。
'use client';
import { use } from 'react';
export function ProductCard ({ productPromise }) {
const productList = use(productPromise);
return <p>Here is the message: {productList}</p>;
}
ここではuse hook
を使用してプロミスからproduct
を取得し、クライアントコンポーネントで使用しています。このように読み込む際にエラーのハンドリングはどうするのかと思いますが、クライアントコンポーネントをSuspense
とError Boundary
を使って、ローディングとエラー状態を処理します。
import { use, Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { fetchproductData } from './api.js';
import { ProductCard } from './ProductCard.jsx';
const App = () => {
const productPromise = fetchproductData();
return;
<ErrorBoundary fallback={<p>エラーが発生しました。</p>}>
<Suspense fallback={<p>Loading...</p>}>
<ProductCard productPromise={productPromise} />
</Suspense>
</ErrorBoundary>;
};
export default App;
エラー処理にError Boundary
を使用したくない場合、Reactはサーバーコンポーネントでエラーを発見し、クライアントコンポーネントに伝える方法を提供しています。↓
import { use, Suspense } from 'react';
import { fetchproductData } from './api.js';
import { ProductCard } from './ProductCard.jsx';
const App = () => {
const productPromise = new Promise((resolve, reject) => {
fetchproductData()
.then(res => resolve(res))
.catch(error => {
resolve(error.message || 'エラーが発生しました。');
});
});
return (
<Suspense fallback={<p>Loading...</p>}>
<ProductCard productPromise={productPromise} />
</Suspense>
);
};
export default App;
useフックを使用してコンテキストを処理する
Context
から値を取得するためにはuseContex
tを使用する必要がありました。
今ではuse hook
を使ってクライアントコンポーネントでContext
の値を使用できます。
AppContext
を使用してUIのテーマを切り替える例です。
Context
は現在のテーマ(ライトテーマとダークテーマ)とテーマを切り替える関数を提供します。
クライアントコンポーネントでは、use hook
を使用してこのContext
の値を取得し、現在のテーマに応じてUIのスタイルを変更し、ボタンクリックでテーマを切り替えることができます。
'use client';
import { createContext, useState } from 'react';
export const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((currentTheme) => (currentTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
クライアントコンポーネントでは、次のようにuse hook
を使用してテーマを適用し、変更することができます。
'use client';
import { ThemeContext } from '@/contexts/theme-context';
import { use } from 'react';
const ThemeSwitcher = () => {
const { theme, toggleTheme } = use(ThemeContext);
return (
<div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff', padding: '10px' }}>
<h1>This is a {theme} theme!</h1>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
};
export default ThemeSwitcher;
if文の中でuse hook
を使用する例です。ユーザーがアクティブな場合にのみテーマ切り替えボタンを表示する例です。
'use client';
import { useState } from 'react';
import { ThemeContext } from '@/contexts/theme-context';
import { use } from 'react';
const ConditionalThemeSwitcher = () => {
const [isActive, setIsActive] = useState(false);
const { theme, toggleTheme } = use(ThemeContext);
if (!isActive) {
return (
<div>
<h1>Activate theme switcher to see the button</h1>
<button onClick={() => setIsActive(true)}>Activate</button>
</div>
);
}
return (
<div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff', padding: '10px' }}>
<h1>This is a {theme} theme!</h1>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
};
export default ConditionalThemeSwitcher;
このコードは、isActive
の状態に応じてテーマ切り替えボタンを表示または非表示にします。
use hook
を使用して条件付きレンダリングを処理できることを示す例です。
結論
use hook
の導入は、React19で開発者がサーバーコンポーネントとクライアントコンポーネント間のデータ交換をより効率的に扱えるようにする重大な変化だと思います。この新しいhook
を通じて、今ではif文やループのようなプログラミング構造内でもhookを使用できるようになり、特に、プロミスとコンテキストをよりシンプルで直感的に扱えるようになり、データローディングや状態管理などの作業をより簡潔で効果的に行えるようになります。
また、サーバーコンポーネント(RSC)との組み合わせは、サーバーサイドレンダリングを活用するReactアプリケーションのパフォーマンスとユーザーエクスペリエンスを大幅に向上させると思います。
サーバーでレンダリングされたコンポーネントをクライアントに効率的に送信し、クライアントでは必要なデータや状態をサーバーから受け取り、即座に使用できるようになることで、アプリケーションの初期ローディング時間を短縮し、全体的な反応速度を改善できます。
Discussion