投稿日:2024/10/29
更新日:2024/10/29
現場でちょいちょい出てくるのでアウトプットです
例えば親コンポーネントの中にコンポーネント1があり、コンポーネント1の中にコンポーネント2、コンポーネント2の中にコンポーネント3があるとします。
この場合、useContextを使わないケースでは親コンポーネントで設定した値はpropsでコンポーネント1=>コンポーネント2=>コンポーネント3のように渡す必要があります。
これだともっとコンポーネントが増えた時に辛くなります。そういったシーンで利用します。
useContextを使用すると、親コンポーネントで設定した値を直接子コンポーネントで使用することができます。これにより、中間のコンポーネントを経由せずにデータを受け渡すことができ、コードの簡潔さと保守性が向上します。
useContextの主な利点:
ただし、useContextの使用は適切なシーンで行うべきです。頻繁に変更される値や、アプリケーション全体で使用されない値には、他の状態管理方法を検討することも重要です。
親コンポーネントの中にコンポーネント1があり、コンポーネント1の中にコンポーネント2、コンポーネント2の中にコンポーネント3がある場合に、親コンポーネントで設定したthemeという値をuseContextを利用してコンポーネント3で取得してみます。
親コンポーネント
値を利用したい子コンポーネント
といった感じです。実際コードでみてみましょう。
親コンポーネント
'use client';
import Sample1 from '@/components/Sample1';
import { createContext, useState } from 'react';
// createContextでコンテキスト作成
export const themeContext = createContext<string>('white');
// 作成したコンテキストのプロバイダーで必要な箇所をラップ、valueに子要素で使いたいもの渡す
export default function Home() {
const [theme, setTheme] = useState<string>('white');
return (
<themeContext.Provider value={theme}>
<Sample1 />
<div className="flex items-center mb-4">
<input onChange={() => setTheme('dark')} type="radio" name="theme" />
<label htmlFor="default-radio-1">dark</label>
</div>
<div className="flex items-center">
<input onChange={() => setTheme('white')} type="radio" name="theme" />
<label htmlFor="default-radio-2">white</label>
</div>
</themeContext.Provider>
);
}
子コンポーネントたち
import Sample2 from '@/components/Sample2';
const Sample1 = () => {
return <Sample2 />;
};
export default Sample1;
import Sample3 from '@/components/Sample3';
const Sample2 = () => {
return <Sample3 />;
};
export default Sample2;
利用コンポーネント
import { themeContext } from '@/app/page';
import { useContext } from 'react';
const Sample3 = () => {
// useContextで設定した値受け取る
const theme = useContext(themeContext);
return (
<>
<p>{theme}</p>
</>
);
};
export default Sample3;
とこんな感じでやるとラジオボタンで設定した値がコンポーネント3で表示できると思います。
これだけだと面白くないので、親コンポーネントを以下のように変更すればバックグラウンドカラーを変えてみましょう。
'use client';
import Sample1 from '@/components/Sample1';
import { createContext, useState } from 'react';
export const themeContext = createContext<string>('white');
export default function Home() {
const [theme, setTheme] = useState<string>('white');
return (
<themeContext.Provider value={theme}>
<div
className={`flex flex-col items-center justify-center min-h-screen transition-colors duration-500 ${
theme === 'dark' ? 'bg-gray-900 text-white' : 'bg-white text-gray-900'
}`}
>
<Sample1 />
<div className="flex items-center mb-4">
<input
onChange={() => setTheme('dark')}
type="radio"
name="theme"
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
/>
<label
htmlFor="default-radio-1"
className="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300"
>
dark
</label>
</div>
<div className="flex items-center">
<input
onChange={() => setTheme('white')}
type="radio"
name="theme"
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
/>
<label
htmlFor="default-radio-2"
className="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300"
>
white
</label>
</div>
</div>
</themeContext.Provider>
);
}
今回は利用方法についてのみまとめましたがこういうグローバル系はレンダリングの最適化に良くなかったりもするので利用シーンは考えないとなぁと思いました。