Amend the state in React using the context Api and useContext hook
In this article we are going to see, step by step, an example of how to amend or update the React state when you are using the context api and the useContext hook.
To be able to see clearly how it works we have to split the code in 3 files. The "PersonDetails.tsx" file, the "prepareContext.tsx" and "index.tsx".
Inside "prepareContext.tsx" file
This is the place where we create the context. Currently we only have this context needed for the demo, the "PersonContext", but is very likely that we may have to create other exports so it is a good idea to isolate the "PersonContext" here and to import it later as needed in other files.
import React, { createContext } from "react";
export const PersonContext = createContext(null);
The "PersonDetails.tsx" file
This is the file which contains the component that is going to be nested inside the context provider. Nested at as many levels as required. For the purpose of this demo I've created a parent component named "Wrapper" (you will see it later in index.tsx) which demonstrates clearly that we are not passing the state via props.
Here we import the context and we pass it to the "useContext" hook invocation. We don't need to use a "Consumer" anymore.
This is what allows us to retrieve the state, personSize in this case and the function that is required to update the state, named togglePersonSize.
The return statement presents to the user the text from the state and the button which has as click event togglePersonSize.
import React, { useContext } from "react";
import { PersonContext } from "./prepareContext";
function PersonDetails() {
const { personSize, togglePersonSize } = useContext(PersonContext);
return (
<div>
<p>
The person is <em>{personSize}</em>
</p>
<button onClick={togglePersonSize}>Change the size</button>
</div>
);
}
export default PersonDetails;
The "index.tsx" file
index.tsx, the place where all the things are coming together.
Here you can see the Wrapper component which acts as the parent component for PersonDetails.
The state and the toggler function are intialized in the top component and then are passed to the
PersonContext.Provider inside the "value" prop.
As you can see, the state is not drilled down via props.
import React, { useState } from "react";
import PersonDetails from "./PersonDetails";
import { createRoot } from "react-dom/client";
import { PersonContext } from "./prepareContext";
// Presentational component
const Wrapper = ({ children }) => (
<div>
Children: <div> {children} </div>
</div>
);
function App() {
const [personSize, setPersonSize] = useState("small");
function togglePersonSize() {
setPersonSize((personSize) => (personSize === "small" ? "big" : "small"));
}
return (
<PersonContext.Provider value={{ personSize, togglePersonSize }}>
<Wrapper>
<PersonDetails />
</Wrapper>
</PersonContext.Provider>
);
}
const container = document.getElementById("root");
const root = createRoot(container);
root.render(<App />);
Helpful links.
useContext docs eactjs.org/docs/hooks-reference.html#usecontext
React context api docs reactjs.org/docs/context.html
Thank you for reading.