Updating a React context from its consumer

This post is free for all to read thanks to the investment Mindsers Club members have made in our independent publication. If this work is meaningful to you, I invite you to join the club today.

Among the last novelties of ReactJS that have greatly bettered the DX (Developer eXperience) of the framework, there is the Context API and hooks. In this post, we'll talk about Context API.

I am not going to detail how the Context API works in this post. If you don't know what that is, I encourage you to go read the very good React documentation on the matter.

Thanks @alexislepresle for the post idea ! You can contribute to the blog too by telling me what you'd like to read about here on the Discord server.

How to modify a context from one of its children?

Just to remind you, the Context API allows data storage and makes it accessible to any child component who want to use it. This is valid whatever level of component graph the children is in.

const MyContext = React.createContext()

const MyComponent = () => {
  const count = useContext(MyContext)

  return (
    <div>price: {count}</div>
  )
}

const App = () => (
  <MyContext.Provider value={2}>
    <div>
      <MyComponent />
      <MyComponent />
    </div>
  </MyContext.Provider>
)

If we simplify it as much as we can, contexts are used to pass an information from the top to the bottom of the component tree. How could we do it the other way around? Or how could we modify context without passing the information to the top?

By using functions and closures. As those have simple values like the others, you can store functions in your context. If you store a function that is able to modify the content of the context, every child will be able to use it and to modify it.

To make the values of the context easier to modify, I am going to use the reference from JavaScript (inspired by C, of course).

const MyContext = React.createContext()

const MyComponent = () => {
  const { count } = useContext(MyContext)

  return (
    <div>price: {count}</div>
  )
}

const App = () => {
  const [count] = useState(0)

  return (
    <MyContext.Provider value={{ count }}>
      <div>
        <MyComponent />
        <MyComponent />
      </div>
    </MyContext.Provider>
  )
}

With the previous code, we obtained the same result. We simply moved data storage toward the state of the parent component.

Now we just have to add a function that modify this state to be able to apply the modification from a child.

const MyContext = React.createContext()

const MyComponent = () => {
  const { count, increment } = useContext(MyContext)

  return (
    <div onClick={increment}>price: {count}</div>
  )
}

const App = () => {
  const [count, updateCount] = useState(0)
  function increment() {
    updateCount(count + 1)
  }

  return (
    <MyContext.Provider value={{ count, increment }}>
      <div>
        <MyComponent />
        <MyComponent />
      </div>
    </MyContext.Provider>
  )
}

Now, when the user clicks on the price, it increases by 1 each time.

To sum up, we are storing data in the state of the component in which we want to use context, and we create a function that can modify this state. Then, you pass the state and the function as context values.

It then becomes possible from the child to get the modification function and to use it to update your context.


To dig a little deeper:

Join 250+ developers and get notified every month about new content on the blog.

No spam ever. Unsubscribe in a single click at any time.

If you have any questions or advices, please create a comment below! I'll be really glad to read you. Also if you like this post, don't forget to share it with your friends. It helps a lot!