Memoize context values
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 MyContext = React.createContext();
const MyContextProvider = ({ children }) => {
const [state, dispatch] = React.useReducer(reducer, { count: 0 });
return (
<MyContext.Provider
value={{ state, dispatch }}
>
{children}
</MyContext.Provider>
);
};
const ButtonParent = () => {
const { dispatch } = React.useContext(MyContext);
const handleButtonClick = React.useCallback(() => {
dispatch({ type: 'increment' });
}, [dispatch]);
return (
<ButtonIncrease onClick={handleButtonClick} />
);
}
let buttonIncreaseRenders = 0;
const ButtonIncrease = React.memo(({ onClick }) => {
buttonIncreaseRenders += 1;
return (
<div className="block">
<button type="input" onClick={onClick}>+ 1</button>
This button rendered {buttonIncreaseRenders} times
</div>
);
});
let buttonDecreaseRenders = 0;
const ButtonDecrease = () => {
const { dispatch } = React.useContext(MyContext);
const handleButtonClick = React.useCallback(() => {
dispatch({ type: 'decrement' });
}, [dispatch]);
return React.useMemo(() => {
buttonDecreaseRenders += 1;
return (
<div className="block">
<button type="input" onClick={handleButtonClick}>- 1</button>
This button rendered {buttonDecreaseRenders} times
</div>
);
}, [handleButtonClick]);
}
const StateCount = () => {
const { state } = React.useContext(MyContext);
return (
<div className="block">
<strong>Counter: {state.count}</strong>
</div>
)
};
const App = props => {
return (
<MyContextProvider>
<h1>Memoize context values</h1>
<StateCount />
<ButtonParent />
<ButtonDecrease />
</MyContextProvider>
);
};
ReactDOM.render(<App />,...