-
-
Save sumanbh/749fa78b635109158e16c21abda7b66f to your computer and use it in GitHub Desktop.
better createContext APIs with setters, and no default values, in Typescript
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
// create context with no upfront defaultValue | |
// without having to do undefined check all the time | |
function createCtx<A>() { | |
const ctx = React.createContext<A | undefined>(undefined) | |
function useCtx() { | |
const c = React.useContext(ctx) | |
if (!c) throw new Error("useCtx must be inside a Provider with a value") | |
return c | |
} | |
return [useCtx, ctx.Provider] as const | |
} | |
// usage - no need to specify value upfront! | |
export const [useCtx, SettingProvider] = createCtx<string>() | |
export function App() { | |
// get a value from a hook, must be in a component | |
const key = useLocalStorage('key') | |
return ( | |
<SettingProvider value={key}> | |
<Component /> | |
</SettingProvider> | |
) | |
} | |
export function Component() { | |
const key = useCtx() // can still use without null check! | |
return <div>{key}</div> | |
} | |
function useLocalStorage(a: string) { | |
return 'secretKey' + a | |
} |
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
type ReducerType<State> = (state: State, action: State) => State | |
export function createCtx<A>(defaultValue: A, reducer: ReducerType<A>) { | |
type DispatchType = React.Dispatch<typeof defaultValue> | |
const defaultDispatch: DispatchType = () => defaultValue | |
const ctx = React.createContext({ state: defaultValue, dispatch: defaultDispatch }) | |
function Provider(props: React.PropsWithChildren<{}>) { | |
const [state, dispatch] = React.useReducer(reducer, defaultValue) | |
return <ctx.Provider value={{ state, dispatch }} {...props} /> | |
} | |
return [ctx, Provider] as const | |
} | |
// usage | |
enum States { | |
Green, | |
Red, | |
Yellow | |
} | |
function reducer(state: States) { | |
if (state === States.Green) return States.Yellow | |
if (state === States.Yellow) return States.Red | |
return States.Green | |
} | |
const [ctx, TextProvider] = createCtx(States.Green, reducer) | |
export const TextContext = ctx | |
export function App() { | |
return ( | |
<TextProvider> | |
<Component /> | |
</TextProvider> | |
) | |
} | |
export function Component() { | |
const { state, dispatch } = React.useContext(ctx) | |
return ( | |
<div> | |
{state} | |
<button onClick={() => dispatch(state)}>Toggle</button> | |
</div> | |
) | |
} |
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
export function createCtx<A>(defaultValue: A) { | |
type UpdateType = React.Dispatch<React.SetStateAction<typeof defaultValue>> | |
const defaultUpdate: UpdateType = () => defaultValue | |
const ctx = React.createContext({ state: defaultValue, update: defaultUpdate }) | |
function Provider(props: React.PropsWithChildren<{}>) { | |
const [state, update] = React.useState(defaultValue) | |
return <ctx.Provider value={{ state, update }} {...props} /> | |
} | |
return [ctx, Provider] as const | |
} | |
// usage | |
const [ctx, TextProvider] = createCtx("someText") | |
export const TextContext = ctx | |
export function App() { | |
return ( | |
<TextProvider> | |
<Component /> | |
</TextProvider> | |
) | |
} | |
export function Component() { | |
const { state, update } = React.useContext(ctx) | |
return ( | |
<label> | |
{state} | |
<input type="text" onChange={e => update(e.target.value)} /> | |
</label> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment