DEV Community

Cover image for The React Context hell
Alfredo Salzillo
Alfredo Salzillo

Posted on

The React Context hell

What is the React Context hell?

Like the callback hell, usual when jQuery was used for everything, the React Context hell is the nasty code you get taking advantage of the React Context API.

const App = () => {
  // ... some code
  return (
    <>
     <ReduxProvider value={store}>
      <ThemeProvider value={theme}>
       <OtherProvider value={otherValue}>
        <OtherOtherProvider value={otherOtherValue}>
         {/** ... other providers*/}
                                <HellProvider value={hell}>
                                  <HelloWorld />
                                </HellProvider>
         {/** ... other providers*/}
        </OtherOtherProvider>
       </OtherProvider>
      </ThemeProvider>
     </ReduxProvider>
    </>
  )
}
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025

How to fix it?

To clean up the nasty code you get from taking advantage of React Context API we need a way to nest multiple Context.Provider without passing them as children of each other.

To achieve that we can use the React.cloneElement API.

The cloneElement API

React.cloneElement(
  element,
  [props],
  [...children]
)
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025

Clone and return a new React element using element as the starting point. The resulting element will have the original element’s props with the new props merged in shallowly. New children will replace existing children. key and ref from the original element will be preserved.

We can use the cloneElement API to reduce a collection of providers, this way we don't have to nest them inside each other.

return [
  <ReduxProvider value={store} />,
  <ThemeProvider value={theme} />,
  <OtherProvider value={otherValue} />,
  <OtherOtherProvider value={otherOtherValue} />,
  // ...others,
  <HellProvider value={hell} />,
  <HelloWorld />,
].reduceRight((prev, provider) => React.cloneElement(provider, {}, prev))
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025

The last element of the array is the content of the app.

Using reduceRight we preserve the nesting to make the HelloWorld element a child of all the providers.

To make it simpler to use we can implement a MultiProvider component.

import React from 'react'

const nest = (
  children: React.ReactNode,
  component: React.ReactElement
) => React.cloneElement(component, {}, children)

export type MultiProviderProps = React.PropsWithChildren<{
  providers: React.ReactElement[]
}>

const MultiProvider: React.FC<MultiProviderProps> = ({
  children,
  providers
}) => (
  <React.Fragment>
    {providers.reduceRight(nest, children)}
  </React.Fragment>
)

export default MultiProvider
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025

Now we can refactor the example using the MultiProvider.

const App = () => {
  return (
    <MultiProvider
      providers={[
        <ReduxProvider value={store} />,
        <ThemeProvider value={theme} />,
        <OtherProvider value={otherValue} />,
        <OtherOtherProvider value={otherOtherValue} />,
        // ...others,
        <HellProvider value={hell} />,
      ]}
    >
      <HelloWorld />
    </MultiProvider>
  )
}
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025

You can find an implementation of MultiProvider inside the react-pendulum library.

GitHub logo alfredosalzillo / react-pendulum

A React Context utility library.

react-pendulum

A React Context utility library.

NPM JavaScript Style Guide codecov

Install

Using npm

npm install --save react-pendulum
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025

Using yarn

yarn add react-pendulum
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025

Components

MultiProvider

A component to clean up the nasty code you get from taking advantage of React Context API.

Props

  • providers the array of providers instances to wrap to the children
import React, { Component, createContext } from 'react'
import { MultiProvider } from 'react-pendulum'
const FirstNameContext = createContext<string>('John')
const LastNameContext = createContext<string>('Doe')

const HelloWorld = () => {
  const firstName = useContext(FirstNameContext)
  const lastName = useContext(LastNameContext)
  return <>{`Hello ${firstName} ${lastName}`}</>
}

class App extends Component {
  render() {
    return (
      <MultiProvider
        providers={[
          <FirstNameContext.Provider value='Yugi' />,
          <
…
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025

Top comments (19)

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
d3352d0d-bf45-4b8d-b0dc-04ac7b profile image
​​​​​​ •
// src/components/AppProviders.js

export default function AppProviders({ children }) {
  return (
    <Context1 value={value}>
      <Context2 value={value2}>
        <Context3 value={value3}>{children}</Context3>
      </Context2>
    </Context1>
  );
}
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
// src/index.js

import ReactDOM from "react-dom";
import App from "./App";
import AppProviders from './components/AppProviders'

const rootElement = document.getElementById("root");
ReactDOM.render(
  <AppProviders>
    <App />
  </AppProviders>,
  rootElement
);
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
stereoplegic profile image
Mike Bybee •

Exactly. No point digging into internals when you can just import.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
727021 profile image
Andrew Schimelpfening •

This looks way cleaner IMO. Keep it simple and easy to read.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
acro5piano profile image
Kay Gosho •

Agree.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
pengeszikra profile image
Peter Vivo •

Good point to alert context hell!
I simple skip use context, instead works with simple useReducer, and pass down actions and state in props. That way give more simple component, because my component don't have outer dependency - expect props, so easy join together in quite complex app.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
dorshinar profile image
Dor Shinar •

Why is it better?

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
shadowtime2000 profile image
shadowtime2000 •

I am wondering this to. It seems like unnecessary complexity and abstraction that makes the code just look messier.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
ivanjrmc profile image
Ivan Jeremic • • Edited

My last article is on this topic dev.to/ivanjeremic/to-use-context-...

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
codyseibert profile image
Cody Seibert •

You could just use a real state management library instead of context.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
alfredosalzillo profile image
Alfredo Salzillo •

For example?

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
linhtch90 profile image
Linh Truong Cong Hong •

Recoil?

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 Thread
 
alfredosalzillo profile image
Alfredo Salzillo •

So you don't use react router and have a BrowserRouter in your code? Or if you use CSS in JS solution, you don't have a kind of ThemeProvider? Or you put both in a recoil state?
Ah and you still need the RecoilRoot, a provider.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025 Thread
 
codyseibert profile image
Cody Seibert •

I could see what you mean, but no we use riot router, don’t do css in js, and use cerebral js, so we have maybe one provider nested out app.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
k_penguin_sato profile image
K-Sato •

Having a bit too many react contexts was very relatable! Didn't even know the React.cloneElement API till now! Thank you!

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
jdgamble555 profile image
Jonathan Gamble •

I think I made an even simpler one here - dev.to/jdgamble555/freakin-easy-re..., let me know your thoughts

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
bwca profile image
Volodymyr Yepishev •

That's pretty neat 🤓

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
linhtch90 profile image
Linh Truong Cong Hong •

I wish React could have something like Services of Angular.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
alfredosalzillo profile image
Alfredo Salzillo •

You can use mobx if you want some spaghetti 🍝 in your project.

🔴 Hot News: alfredosalzillo/the react context hell p - Kapook Update 2025
 
roselpadilla profile image
Rosel •

KISS advocates: 👁👄👁

Some comments may only be visible to logged-in visitors. Sign in to view all comments.