Split state and dispatch contexts
by Niels Krijger
HTML
<div id="app"></div>
CSS
body {
background-color: #F2F5F6;
font-family: sans-serif;
}
button {
min-width: 3em;
height: 2em;
text-align: center;
}
h1 {
font-size: 2em;
font-weight: bold;
padding-bottom: .3em;
}
h2 {
font-size: 1.5em;
font-weight: bold;
}
div {
padding: .5em 1em;
}
React
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
}
const StateContext = React.createContext();
const DispatchContext = React.createContext();
const MyContextProvider = ({ children }) => {
const [state, dispatch] = React.useReducer(reducer, { count: 0 });
return (
<DispatchContext.Provider value={dispatch}>
<StateContext.Provider value={state}>
{children}
</StateContext.Provider>
</DispatchContext.Provider>
);
};
let button1renders = 0;
const Button1 = () => {
button1renders += 1;
const dispatch = React.useContext(DispatchContext);
return (
<div className="block">
<button type="input" onClick={() => dispatch({ type: 'increment' }) }>+ 1</button>
This button rendered {button1renders} times
</div>
);
}
let button2renders = 0;
const Button2 = () => {
button2renders += 1;
const dispatch = React.useContext(DispatchContext);
return (
<div className="block">
<button type="input" onClick={() => dispatch({ type: 'decrement' }) }>- 1</button>
This button rendered {button2renders} times
</div>
);
}
const StateCount = () => {
const state = React.useContext(StateContext);
return (
<div className="block">
<strong>Counter: {state.count}</strong>
</div>
)
};
const App = props => {
return (
<MyContextProvider>
<h1>Split state and dispatch contexts</h1>
<StateCount />
<Button1 />
<Button2 />
</MyContextProvider>
);
};
ReactDOM.render(<App />, document.getElementById('app'));