React createContextでグローバルなStateを作成する
React
+TypeScript
の環境で、createContext
を使用して、グローバルな状態State
(グローバル変数)を作成します。
Providerの作成
まずは以下のようにグローバル変数の型を作成します。
今回はAppContext
という名前で、ローディング状態とローディング状態を設定する関数を定義しています。
AppProvider.tsx
export const AppContext = createContext<
| {
logding: boolean;
setLoading: (show: boolean) => void;
}
| undefined
>(undefined);
AppContext.displayName = 'AppContext';
次にコンポーネントを作成する要領で、グローバルな変数を定義します。
AppProvider.tsx
type 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.ts
import { 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.tsx
import useApp from './useApp';
const MyComponent = () => {
// contextの値を参照可能
const { loading, setLoading } = useApp();
};
グローバル変数を定義する別の方法として、Recoil
を使用する方法があります。
Recoil
を使用したグローバル変数の作成方法についてはReact RecoilでグローバルなStateを作成するで紹介しています。