Skip to content

Instantly share code, notes, and snippets.

@7iomka
Created September 20, 2023 18:35
Show Gist options
  • Save 7iomka/8fd3c517ddfb40b82b7f1c7265ecea83 to your computer and use it in GitHub Desktop.
Save 7iomka/8fd3c517ddfb40b82b7f1c7265ecea83 to your computer and use it in GitHub Desktop.
Create react context typed
import type { ReactNode } from 'react';
import { useContext, createContext, useMemo } from 'react';
export const createReactContext = <ContextValueType extends object | null>(
rootComponentName: string,
defaultContext?: ContextValueType,
) => {
const Context = createContext<ContextValueType | undefined>(defaultContext);
const Provider = (props: ContextValueType & { children: ReactNode }): JSX.Element => {
const { children, ...providerProps } = props;
// Only re-memoize when prop values change
const value = useMemo(
() => providerProps,
// eslint-disable-next-line react-hooks/exhaustive-deps
Object.values(providerProps),
) as ContextValueType;
return <Context.Provider value={value}>{children}</Context.Provider>;
};
const useReactContext = (consumerName: string): ContextValueType => {
const context = useContext(Context);
if (context) return context;
if (defaultContext !== undefined) return defaultContext;
throw new Error(`\`${consumerName}\` must be used within \`${rootComponentName}\``);
};
Provider.displayName = `${rootComponentName}Provider`;
return [Provider, useReactContext] as const;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment