Skip to content

Instantly share code, notes, and snippets.

@iamandrewluca

iamandrewluca/App.tsx

Last active Sep 28, 2020
Embed
What would you like to do?
import * as React from "react";
import "./styles.css";
import { useCountState, useCountDispatch } from "./count-context";
export default function App() {
const count = useCountState();
const dispatch = useCountDispatch();
return (
<div className="App">
{count}
<h1 onClick={() => dispatch({ type: "increment" })}>Hello CodeSandbox</h1>
<h2 onClick={() => dispatch({ type: "decrement" })}>
Start editing to see some magic happen!
</h2>
</div>
);
}
import { kentcdoddsProvides } from "./kentcdodds-provides";
type State = number;
type Action = { type: "increment" } | { type: "decrement" };
function reducer(state: State, action: Action): State {
switch (action.type) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
default:
// @ts-ignore
throw new Error(`Unhandled action type: ${action.type}`);
}
}
const initialState = 0;
const [
CountProvider,
useCountState,
useCountDispatch,
useCount
] = kentcdoddsProvides(reducer, initialState, {
provider: "CountProvider",
stateHook: "useCountState",
dispatchHook: "useCountDispatch"
});
export { CountProvider, useCountState, useCountDispatch, useCount };
import * as React from "react";
import { render } from "react-dom";
import { CountProvider } from "./count-context";
import App from "./App";
const rootElement = document.getElementById("root");
render(
<CountProvider>
<App />
</CountProvider>,
rootElement
);
import React, {
Reducer,
ReducerState,
Dispatch,
ReducerAction,
PropsWithChildren
} from "react";
type Names = {
provider: string;
stateHook: string;
dispatchHook: string;
};
export function kentcdoddsProvides<R extends Reducer<any, any>>(
reducer: R,
initialState: ReducerState<R>,
names: Names = {
provider: "Provider",
stateHook: "useState",
dispatchHook: "useDispatch"
}
): [
(props: PropsWithChildren<{}>) => JSX.Element,
() => ReducerState<R>,
() => Dispatch<ReducerAction<R>>,
() => [ReducerState<R>, Dispatch<ReducerAction<R>>]
] {
const StateContext = React.createContext<ReducerState<R> | undefined>(
undefined
);
const DispatchContext = React.createContext<
Dispatch<ReducerAction<R>> | undefined
>(undefined);
function Provider(props: PropsWithChildren<{}>) {
const [state, dispatch] = React.useReducer(reducer, initialState);
return (
<StateContext.Provider value={state}>
<DispatchContext.Provider value={dispatch}>
{props.children}
</DispatchContext.Provider>
</StateContext.Provider>
);
}
function useState() {
const context = React.useContext(StateContext);
if (context === undefined) {
throw new Error(
`${names.stateHook} must be used within a ${names.provider}`
);
}
return context;
}
function useDispatch() {
const context = React.useContext(DispatchContext);
if (context === undefined) {
throw new Error(
`${names.dispatchHook} must be used within a ${names.provider}`
);
}
return context;
}
function useStateAndDispatch(): [
ReducerState<R>,
Dispatch<ReducerAction<R>>
] {
return [useState(), useDispatch()];
}
return [Provider, useState, useDispatch, useStateAndDispatch];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.