{ Soham Kamani }

AboutBlog GithubTwitter

How to combine React Contexts ↗️

If you just want to see the example source code, you can find it here

The React Context API is used for passing down data to all the child components that need it. You can think of it as a global state, which you do not need to pass down through intermediary components.

Sometimes, you will need to use two or more contexts together. But as you can see in the official example and in the example below, it can get a bit messy:

// MyContext is used to pass in the greeting
const MyContext = React.createContext()
// ThemeContext is used to pass in the color of the text
const ThemeContext = React.createContext()

const OuterComponent = () => (
  <div>
    <MiddleComponent />
  </div>
)
const MiddleComponent = () => (
  <div>
    <InnerComponent />
  </div>
)

// InnerComponent uses the context values
const InnerComponent = () => (
  // We need to wrap the element we want to render inside both consumers
  <MyContext.Consumer>
    {(greeting) => (
      <ThemeContext.Consumer>{(color) => <div style={{ color: color }}>Hello {greeting}</div>}</ThemeContext.Consumer>
    )}
  </MyContext.Consumer>
)

const root = (
  <MyContext.Provider value='world'>
    <ThemeContext.Provider value='red'>
      <OuterComponent />
    </ThemeContext.Provider>
  </MyContext.Provider>
)
// root will be rendered

Everytime we want to use both the contexts together, we have to wrap our components with both of the providers and consumers. This would get even worse if we needed to use more than two contexts.

Creating a combined context

We can wrap the consumers and providers to create a combined consumer and provider respectively:

const CombinedContextProvider = ({ greeting, color, children }) => (
  <MyContext.Provider value={greeting}>
    <ThemeContext.Provider value={color}>{children}</ThemeContext.Provider>
  </MyContext.Provider>
)

const CombinedContextConsumer = ({ children }) => (
  <MyContext.Consumer>
    {(greeting) => (
      <ThemeContext.Consumer>{(color) => children({ greeting, color })}</ThemeContext.Consumer>
    )}
  </MyContext.Consumer>
)

We can then use the combined consumer and provider in almost the same way we use a regular context component:

// OuterComponent and MiddleComponent are the same as before

const InnerComponent = () => (
  // The combined consumer gives us the greeting and color as the arguments
  <CombinedContextConsumer>
    {({ greeting, color }) => <div style={{ color: color }}>Hello {greeting}</div>}
  </CombinedContextConsumer>
)

const root = (
  // You can pass the values of each individual context as 
  // separate props to the combined provider
  <CombinedContextProvider greeting='world' color='red'>
    <OuterComponent />
  </CombinedContextProvider>
)

You can find the full example code for combining contexts here


Like what I write? Join my mailing list, and I'll let you know whenever I write another post

Comments

Soham Kamani

Written by Soham Kamani, an author,and a full-stack developer who has extensive experience in the JavaScript ecosystem, and building large scale applications in Go. He is an open source enthusiast and an avid blogger. You should follow him on Twitter