React Context provides a convenient way to manage state globally without the need for prop drilling. Prop drilling can be a tedious and error-prone process of passing props from a parent component to deeply nested child components through a chain of intermediary components. As the component tree grows in complexity, prop drilling can make the code harder to read and maintain, and it can lead to rendering issues in some cases. For instance, when a parent component prop changes, all child components that depend on it will re-render, regardless of whether the change affects their behavior or not. This can result in unnecessary re-renders that can negatively impact the application's performance. Furthermore, passing deeply nested or large amounts of data through props can also impact performance by bloating the component tree and causing rendering delays. To overcome these challenges, React provides a solution to this problem: the useContext hook. This hook allows you to manage state globally, without the need for props drilling. In this post, we'll take a closer look at the useContext hook and how it can help you manage state more efficiently.
What is React Context?
Before we dive into the useContext hook, let's first talk about React Context. Context is a way to share state between components without passing it down through props. It provides a way to share data that can be considered "global" for a tree of React components, such as the current user's authentication status or the theme of the application.
With Context, you can avoid passing props through intermediate elements and focus on providing data to the components that need it. Context allows you to update state in one place and have those changes reflected throughout your application.
What is Prop Drilling?
Prop drilling is the process of passing down props (properties) from a parent component to a deeply nested child component through a series of intermediary components. Prop drilling can make the code harder to read and maintain, especially as the component tree grows in complexity.
Prop drilling can potentially lead to rendering issues in certain situations. When a prop changes in a parent component, all child components that depend on that prop will need to re-render, even if the change doesn't affect their own logic or behavior. This can cause unnecessary re-renders and impact the performance of the application.
How does useContext solve the problem?
To avoid these problems, we use the useContext hook. The useContext hook allows us to access a Context object and read its value. We can then use this value to manage state globally without the need for prop drilling.
By using the useContext hook, we can access a shared state from any component in the tree without the need for intermediate components to pass the state down. This makes the code easier to read and maintain and can lead to better performance.
How to use the useContext hook?
Using the useContext hook is relatively simple. First, we need to create a Context object using the createContext method provided by React. We can then provide a default value for the Context using the Provider component.
Once we have created the Context object, we can use the useContext hook in any component that needs to access the shared state. We simply import the useContext hook and pass in the Context object as an argument. This gives us access to the shared state and allows us to manage it as needed.
Examples:
Source Code Link
DataContext.js
import { createContext, useState, useEffect } from 'react';
import useAxiosFetch from '../hooks/useAxiosFetch';
const DataContext = createContext({});
export const DataProvider = ({ children }) => {
const [posts, setPosts] = useState([])
const [search, setSearch] = useState('');
const [searchResults, setSearchResults] = useState([]);
const { data, fetchError, isLoading } = useAxiosFetch('http://localhost:3500/posts');
useEffect(() => {
setPosts(data);
}, [data])
useEffect(() => {
const filteredResults = posts.filter((post) =>
((post.body).toLowerCase()).includes(search.toLowerCase())
|| ((post.title).toLowerCase()).includes(search.toLowerCase()));
setSearchResults(filteredResults.reverse());
}, [posts, search])
return (
<DataContext.Provider value={{
search, setSearch,
searchResults, fetchError, isLoading,
posts, setPosts
}}>
{children}
</DataContext.Provider>
)
}
export default DataContext;
App.js
import Header from './Header';
import Nav from './Nav';
import Footer from './Footer';
import Home from './Home';
import NewPost from './NewPost';
import PostPage from './PostPage';
import EditPost from './EditPost';
import About from './About';
import Missing from './Missing';
import { Route, Switch } from 'react-router-dom';
import { DataProvider } from './context/DataContext';
function App() {
return (
<div className="App">
<Header title="React JS Blog" />
<DataProvider>
<Nav />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/post" component={NewPost} />
<Route path="/edit/:id" component={EditPost} />
<Route path="/post/:id" component={PostPage} />
<Route path="/about" component={About} />
<Route path="*" component={Missing} />
</Switch>
</DataProvider>
<Footer />
</div>
);
}
export default App;
Illustration:
Conclusion
The useContext hook is a powerful tool for managing state in React applications. It allows us to avoid prop drilling and manage state globally, which can make our code easier to read and maintain. By using the useContext hook, we can improve the performance of our applications and provide a better experience for our users.
Thank you for taking the time to read this blog. I hope it has been informative and has helped you gain a deeper understanding of the topic. If you have any feedback or suggestions for future content, please let me know!