Context API Notes
Introduction
When working with React, you often need to share data between components. The traditional way of passing data is through props. However, as your application grows, passing data through multiple levels of components (called "prop drilling") can become cumbersome and error-prone. This is where Context API comes into play. Context API simplifies state management by allowing you to share state across your component tree without explicitly passing props at every level.
Key Points:
Props within props (prop drilling): Passing data through multiple layers of components is not directly possible without explicitly sending it as props.
Context API and State Management: Context API provides a straightforward way to manage state, but for more complex applications, tools like Redux, Redux Toolkit, or Zustand offer additional features for state management in an organized way.
Injecting Context: Context can be injected at any point in the component tree, giving flexibility in how and where it’s used.
Flow of Code
Here’s an example application demonstrating the use of Context API.
File Structure:
src/
|-- components/
| |-- Login.jsx
| |-- Profile.jsx
|-- context/
| |-- UserContextProvider.jsx
| |-- UserContext.js
|-- App.jsx
|-- App.css
App.jsx
This is the entry point of the application where the Context API is implemented.
import './App.css';
import Login from './components/Login';
import Profile from './components/Profile';
import UserContextProvider from './context/UserContextProvider';
function App() {
// Context API is handled here
return (
<UserContextProvider>
<h1>React with Chai</h1>
<Login />
<Profile />
</UserContextProvider>
);
}
export default App;
Explanation:
The
UserContextProvider
wraps the componentsLogin
andProfile
. This means that both components will have access to the context data provided byUserContextProvider
.The
<h1>
tag is used for display purposes only.Components
Login
andProfile
demonstrate consuming the context.
context/UserContextProvider.jsx
So, UserContext is where the information is stored, and UserContextProvider is the helper that makes sure the information is available to everyone in the app!
This file defines the Context Provider, which wraps around the components that need access to the context data.
import React from 'react';
import UserContext from './UserContext';
// `children` works like a placeholder for nested components, similar to `div` or React Router's `Outlet`.
const UserContextProvider = ({ children }) => {
// State managed within the context
const [user, setUser] = React.useState(null);
// `children` will be wrapped and rendered
return (
// Passing an object with `user` and `setUser` as the context value
<UserContext.Provider value={{ user, setUser }}>
{children}
</UserContext.Provider>
);
};
export default UserContextProvider;
Explanation:
React.useState
is used to manage theuser
state within the provider.UserContext.Provider
wraps the children and provides theuser
state andsetUser
function to all components that consume the context.The
value
prop ofProvider
is used to pass the state and functions.
context/UserContext.js
This file creates the context object.
import React from 'react';
// Creating the context
const UserContext = React.createContext();
// Exporting the context object
export default UserContext;
Explanation:
React.createContext
creates a context object.This context object can be used to share data across components.
When wrapped with a Provider, all components within the Provider's scope can access the data.
components/Login.jsx
This component collects user credentials and updates the context.
import React, { useContext, useState } from 'react';
import UserContext from '../context/UserContext';
const Login = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const { setUser } = useContext(UserContext);
const handleSubmit = (e) => {
// Prevent the default form submission
e.preventDefault();
// Update the context with the user data
setUser({ username, password });
};
return (
<div>
<h2>Login</h2>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder='Username'
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder='Password'
/>
<button onClick={handleSubmit}>Submit</button>
</div>
);
};
export default Login;
Explanation:
Two states,
username
andpassword
, are used to capture user inputs.useContext
fetches thesetUser
function fromUserContext
.On submitting the form, the
setUser
function updates the context with the entered data.
components/Profile.jsx
This component displays the user data from the context.
import React, { useContext } from 'react';
import UserContext from '../context/UserContext';
const Profile = () => {
const { user } = useContext(UserContext);
if (!user) {
return (
<div>
Please login
</div>
);
} else {
return (
<div>
<h1>Welcome {user.username}</h1>
</div>
);
}
};
export default Profile;
Explanation:
useContext
fetches theuser
data fromUserContext
.If
user
is not set, it prompts the user to log in.If
user
is set, it displays a welcome message with the username.
Summary:
Context API avoids the need for prop drilling by providing a way to share data between components directly.
Login and Profile components demonstrate how to update and consume context data.
It’s suitable for medium-sized applications.
Start using Context API today to simplify your state management journey!