React createContextでグローバルなStateを作成する
React+TypeScriptの環境で、createContextを使用して、グローバルな状態State(グローバル変数)を作成します。
Providerの作成
まずは以下のようにグローバル変数の型を作成します。
今回はAppContextという名前で、ローディング状態とローディング状態を設定する関数を定義しています。
AppProvider.tsxexport const AppContext = createContext<
| {
logding: boolean;
setLoading: (show: boolean) => void;
}
| undefined
>(undefined);
AppContext.displayName = 'AppContext';次にコンポーネントを作成する要領で、グローバルな変数を定義します。
AppProvider.tsxtype Props = {
children: ReactNode;
};
const AppProvider = ({ children }: Props) => {
// ローディング状態を管理するステート
const [loading, setLoadingInner] = useState<boolean>(false);
// ローディング状態を変更するファンクション
const setLoading = useCallback((show: boolean) => {
setLoadingInner(show);
}, []);
const value = useMemo(() => {
return {
loading,
setLoading,
};
}, [loading, setLoading]);
return (
<AppContext.Provider value={value}>
{children}
</AppContext.Provider>
);
};
export default AppProvider;このコンポーネントの子要素(children)の全てで、ここで定義した変数を使用できるようになります。
例えば以下のようにすれば、MyComponentのコンポーネントでloadingなどを参照できるようになります。
import AppProvider from './AppProvider';
const App = () => {
return (
<AppProvider>
<MyComponent>
</AppProvider>
);
};参照方法
各コンポーネントでuseContextを使用して参照することができますが、<AppProvider>の外で定義されたコンポーネントの場合、contextはundefinedになります。
各コンポーネントでundefinedのタイプチェックをするのは面倒なので、contextを参照するためのフックを作成します。
useApp.tsimport { useContext } from 'react';
import { AppContext } from './AppProvider';
const useApp = () => {
const context = useContext(AppContext); // contextはundefinedの可能性がある
if (context === undefined) {
throw new Error('useAppはAppProvider配下で使用してください。');
}
return context; // contextはundefinedではない
};各コンポーネントでは、useContextではなくuseAppを使用して、参照します。
MyComponent.tsximport useApp from './useApp';
const MyComponent = () => {
// contextの値を参照可能
const { loading, setLoading } = useApp();
};グローバル変数を定義する別の方法として、Recoilを使用する方法があります。
Recoilを使用したグローバル変数の作成方法についてはReact RecoilでグローバルなStateを作成するで紹介しています。