Last active
September 24, 2021 08:42
-
-
Save kentcdodds/0c3349caf28c53ee383841a02580c9ac to your computer and use it in GitHub Desktop.
A simple context creator that doesn't allow any logic. It's 100% just to make it easy to pass a value from a parent to all children, specifically useful for remix where you just want a loader's data to be accessible anywhere else in your tree.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function createSimpleContext<ContextType>(name: string) { | |
const defaultValue = Symbol(`Default ${name} context value`) | |
const Context = | |
React.createContext<ContextType | null | typeof defaultValue>(defaultValue) | |
Context.displayName = name | |
function useValue() { | |
const user = React.useContext(Context) | |
if (user === defaultValue) { | |
throw new Error(`use${name} must be used within ${name}Provider`) | |
} | |
if (!user) { | |
throw new Error( | |
`No value in ${name}Provider context. If the value is optional in this situation, try useOptional${name} instead of use${name}`, | |
) | |
} | |
return user | |
} | |
function useOptionalValue() { | |
const user = React.useContext(Context) | |
if (user === defaultValue) { | |
throw new Error(`useOptional${name} must be used within ${name}Provider`) | |
} | |
return user | |
} | |
return {Provider: Context.Provider, useValue, useOptionalValue} | |
} | |
const { | |
Provider: UserProvider, | |
useValue: useUser, | |
useOptionalValue: useOptionalUser, | |
} = createSimpleContext<User>('User') | |
// then elsewhere: | |
export default function AppWithProviders() { | |
const data = useRouteData<LoaderData>() | |
return ( | |
<UserProvider value={data.user}> | |
{/* ... */} | |
</UserProvider> | |
) | |
} | |
// and then in a child route somewhere: | |
export default function RequiresAUser() { | |
const user = useUser() | |
// ... | |
} | |
// and in another one where the user is optional: | |
function UserIsOptional() { | |
const user = useOptionalUser() | |
// ... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment