Ecrit par Nathanaël Cherrier

Updating a React context from its consumer

Publié dans ,

Partagez l'article

twitter facebook

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 forum.

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 children 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 juste 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 datas 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 become  possible from the child to get the modification function and to use it to update your context.


To dig a little deeper:

Si vous avez des questions ou des remarques/conseils, n'hésitez pas à en discuter avec les autres membres du forum (zone de commentaires plus bas)! Et si vous aimez l'article, n'oubliez pas de le partager avec vos amis. Vous pouvez aussi soutenir le blog sur Patreon.