React Context using Hooks

Andrew Bliss
4 min readFeb 5, 2020

Hooks have taken the react community by storm. Let’s look at how to implement React Context using hooks.

This code will be using React, Typescript, Material UI, and React Hooks. Context combined with hooks can enable your application to have powerful components. This article will focus on creating an application context and using hooks to keep application state.

For the complete source check out this repo:

import React, { useContext } from 'react';
import useLocalStorage from 'hooks/useLocalStorage';
import CssBaseline from '@material-ui/core/CssBaseline';
import { ThemeProvider } from '@material-ui/styles';
import defaultTheme from 'themes/default';
import darkTheme from 'themes/dark';
interface ContextProps {
darkMode: boolean;
setDarkMode(darkMode: boolean): void;
}
const Context = React.createContext<ContextProps>({
darkMode: false,
setDarkMode: () => {},
});
interface Props {
children?: React.ReactNode;
}
const Provider: React.FC<Props> = ({ children }) => {
const [darkMode, setDarkMode] = useLocalStorage('darkMode', false);
return (
<Context.Provider
value={{
darkMode,
setDarkMode,
}}
>
{children}
</Context.Provider>
);
};
export const useStore = () => useContext(Context);export function withProvider(Component: any) {
return function WrapperComponent(props: any) {
return (
<Provider>
<Component {...props} />
</Provider>
);
};
}
export { Context, Provider };export const useApp = () => {
const { darkMode, setDarkMode } = useStore();
return {
darkMode,
setDarkMode,
};
};
export function withThemeProvider(Component: any) {
const WrapperComponent = ({ props }: any) => {
const { darkMode } = useApp();
const theme = darkMode ? darkTheme : defaultTheme;
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Component {...props} />
</ThemeProvider>
);
};
return withProvider(WrapperComponent);
}

This will create a React Context in which we can store a boolean variable called darkMode, and a setter function called setDarkMode, which can switch between a light and dark mode. You can add any global state you need here for your app. You probably have learned the global state is bad, and it is, be careful.

Now we will create a React Context Provider, which we can use anywhere in our app.

This snippet will create a React Context Provider that will use a custom hook called useLocalStorage.

Check out my article on how to create your own customs hooks, especially the useLocalStorage hook.

Now let’s start exporting our awesome context, so we can use them within our app.

This will export the Context and the Provider to use within our app. But let’s also export some helper functions so we can neatly wrap or components.

The useStore function is our hook into this Context. We will be using this in our component that will switch the theme.

The withProvider function is our wrapper that will enable us to neatly wrap our app component in this context. If you’re not familiar with React Context, here is a link to get caught up.

Now let’s implement our App component to see how to use this Context.

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { withThemeProvider } from './store/Store';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';
import Box from '@material-ui/core/Box';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Switch from '@material-ui/core/Switch';
import { useStore } from './store/Store';
const useStyles = makeStyles(theme => ({
root: {
width: '100%',
height: '100%',
},
}));
const App: React.FC = () => {
const classes = useStyles();
const { darkMode, setDarkMode } = useStore();
return (
<Grid
className={classes.root}
container
justify="center"
alignItems="center"
>
<Paper>
<Box p={10}>
<FormControlLabel
control={
<Switch
checked={darkMode}
onChange={() => setDarkMode(!darkMode)}
/>
}
label="Dark Mode"
/>
</Box>
</Paper>
</Grid>
);
};
export default withThemeProvider(App);

This is our App component that will take in our useApp hook and grab the darkMode and setDarkMode from the context.

It will render a switch component the user can use to switch on or off the dark mode theme.

You probably want to have this switch in a drawer or a user settings page. Once you have the Context, we wrap the app in our withThemeProvider.

Once again, you should keep in mind, when creating a global context like this, the performance of your app. A global context should only store information about the whole app, such as the theme or the logged in user.

Happy hooking !!!

--

--