You want to share data between sibling components? You want to send information between a complex hierarchy of parent & child components? You want to be able to update states from child to parent?
Then this article is for you. Follow the steps to know how to create powerful contexts in React to help share data between components easily with an example focused on a user email shared between two sibling components.
Setup
This example is based on the Vite bundler.
npm install --save-dev --save-exact vite
npm install --save --save-exact react react-dom react-router-dom
HTML entry point
This will serve as the entry point of our website.
touch index.html
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="React">
<title>React</title>
</head>
<body>
<div id="root"></div>
<script src="./index.jsx" type="module"></script>
</body>
</html>
JSX entry point
This is the file that is run when hitting the website.
touch index.jsx
import React from "react";
import {createRoot} from "react-dom/client";
import {App} from "./components/app";
createRoot(document.getElementById("root")).render(
<App />
);
User context
This context is the object that will hold and share our data.
mkdir contexts
touch contexts/user.js
import {createContext} from "react";
export const UserContext = createContext();
User custom hook
We will create a hook to ease the use of the user context.
mkdir hooks
touch hooks/user.js
import {useContext} from "react";
import {UserContext} from "../contexts/user";
export const useUser = () => useContext(UserContext);
User provider
The provider will help us share the user's data will all the components that we allow access to this data.
mkdir providers
touch providers/user.jsx
import React, {useReducer, useMemo, useCallback} from "react";
import {UserContext} from "../contexts/user";
const initialState = {
email: "johndoe@domain.com"
};
const reducer = (state, action) => {
switch (action.type) {
case "UPDATE_EMAIL":
return {
...state,
email: action.payload
};
default:
return state;
}
};
export const UserProvider = ({children}) => {
const [user, dispatch] = useReducer(reducer, initialState);
const updateEmail = useCallback(event => {
dispatch({
type: "UPDATE_EMAIL",
payload: event.target.value
});
});
const value = useMemo(() => {
return {user, updateEmail};
}, [user, updateEmail]);
return (
<UserContext.Provider value={value}>
{children}
</UserContext.Provider>
);
};
User details page
This is a simple page that will illustrate how to read data from our context.
mkdir pages
touch pages/user-details.jsx
import React from "react";
import {useUser} from "../hooks/user";
export const UserDetails = () => {
const {user} = useUser();
return (
<>
<h1>User details</h1>
<p>Email: {user.email}</p>
</>
);
};
User form page
This is yet another simple page that will illustrate how to read and update date from & to our context.
touch pages/user-form.jsx
import React, {useCallback} from "react";
import {useUser} from "../hooks/user";
export const UserForm = () => {
const {user, updateEmail} = useUser();
return (
<div>
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
value={user.email}
onChange={updateEmail} />
</div>
);
};
Application component
This is the component that will hold the logic of our application.
mkdir components
touch components/app.jsx
import React from "react";
import {BrowserRouter, Routes, Route, Link} from "react-router-dom";
import {UserProvider} from "../providers/user";
import {UserDetails} from "../pages/user-details";
import {UserForm} from "../pages/user-form";
export const App = () => {
return (
<BrowserRouter>
<UserProvider>
<header>
<ul>
<li>
<Link to="/user/details">
User details
</Link>
</li>
<li>
<Link to="/user/form">
User form
</Link>
</li>
</ul>
</header>
<main>
<Routes>
<Route
path="/user/details"
element={<UserDetails />} />
<Route
path="/user/form"
element={<UserForm />} />
</Routes>
</main>
</UserProvider>
</BrowserRouter>
);
};
Start
This will start a development server so that we can see the result of our application.
npx vite
Top comments (0)