Simple and reusable React Context API example (HOC)
This is an example of how to use the new React Context API in a modular and concise way, using an HOC.
The example shows how to propagate a theme color across a minimal React app. Demo and sandbox: https://codesandbox.io/s/881np4xqp9
One of the advantages of using react Context is to avoid prop-drilling (passing props down a chain of component), in order to re-render of a set of components. This example is minimal but this pattern works equally with nested components (which is the goal).

Let’s say we have 3 components:
App.js
SetColor.js
Menu.jsMenu.js is a component that will change color depending on the theme:
import * as React from "react";
import { withTheme } from "./ThemeContext/withTheme";const Menu = props => (
<div style={{ backgroundColor: props.themeContext.color }}>
Menu
</div>
);export default withTheme(Menu);
- In 2 lines with code, we can inject a theme color in our Menu component, and read this theme color string from the props
themeContext
SetColor.js is component to set the color of the theme:
import * as React from "react";
import { withTheme } from "./ThemeContext/withTheme";const SetColor = props => (
<div>
<button onClick={() => props.themeContext.setColor("red")}>Red
</button> <button onClick={() => props.themeContext.setColor("blue")}>Blue
</button>
</div>
);export default withTheme(SetColor);
- We inject a themeContext props in our SetColor component, and set the theme color from using
themeContext.setColor()
If we click on a button, it will propagate the color changes to our Menu, blue or red values here.
The achieve this, we only need 3 files, which we will organize under a folder ThemeContext.
App.js
SetColor.js
Menu.js
ThemeContext/
- theme-context.js
- withTheme.js
- ThemeProvider.jstheme-context.js
import * as React from "react";export const ThemeContext = React.createContext(
// default values used by a Consumer when it does not have a
// matching Provider above it in the tree, useful for testing
{
themeContext: {
color: 'blue',
setColor: () => {}
}
}
)
withTheme.js
import * as React from 'react';
import {ThemeContext} from './theme-context';export function withTheme(Component) {
return function ThemeComponent(props) {
return (
<ThemeContext.Consumer>
{(contexts) => <Component {...props} {...contexts} />
}
</ThemeContext.Consumer>
)
}
}
- withTheme.js is our High-Order-Component (HOC), which let us use
export withTheme(AnyComponent)to inject our theme context (themeContextprops) in any component.
ThemeProvider.js
import * as React from 'react';
import {ThemeContext} from './theme-context';export default class ThemeProvider extends React.Component {constructor() {
super();
this.state = {
setColor: this.setColor.bind(this),
color: "yellow"
};
}setColor(color) {
this.setState({color});
}render() {
return (
<ThemeContext.Provider value={{
themeContext: {
...this.state
}
}}>
{this.props.children}
</ThemeContext.Provider>
)
}
}
- ThemeProvider.js is our context component containing our theme
colorstate, and thesetColorfunction to change it. - We are passing the
colorstring and thesetColorfunction in a wrapper objectthemeContextwhich will be the unique props injected by thewithThemeHOC.
We could have passedcolorandsetColoras two props directly without nesting them in athemeContextobject, but I think this indicates clearly what is being injected bywithThemeto a component. This also works well with Flow props typing.
App.js — Finally, let’s not forget to modify App.js:
import * as React from "react";
import ThemeProvider from "./ThemeContext/ThemeProvider";
import Menu from "./Menu";
import SetColor from "./SetColor";export default () => (
<ThemeProvider>
<Menu />
<br />
<SetColor />
</ThemeProvider>
);
ThemeProviderneeds to be above any child component that will consume our theme context. In the example above, the children components are right under it, but they could have been as well nested under 50 sub-components.
Demo and sandbox : https://codesandbox.io/s/881np4xqp9
That’s it! Let me know if that was helpful.
