Did you ever think why does context exists in react? You might have seen people asking on the internet that when to use context or context+useReduer and when to use redux. So let's understand the use cases of context in react and how hooks have made life easier.
React docs define Context as -
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
This means that context helps us in avoiding prop drilling. Wait but why should we avoid prop drilling? What is wrong with prop drilling?
You wouldn't understand why prop drilling is bad until you go through the pain of passing down a single value all the way from the top of the DOM tree to deep down in some component.
Let's see an example of prop drilling...
// App.js
export default function App() {
const [userName] = useState("Mr. Ferb");
return (
<div>
<Dashboard userName={userName} />
</div>
);
}
// Dashboard.js
export default function Dashboard({ userName }) {
return (
<div>
<Profile userName={userName} />
</div>
);
}
// Profile.js
export default function Profile({ userName }) {
return <div>
<h1>Welcome { userName } </h1>
</div>;
}
In the above code, we're trying to pass the username of logged-in user from App component to Profile component. But profile component isn't enclosed inside app but it lies in Dashboard. Dashboard is enclosed in App. So to make this
userName
available to<Profile />
component, we would have to pass it as props to<Dashboard />
first and then from<Dashboard />
again to<Profile />
.Now this was a hypothetical scenario and we were passing just a single value but consider the real complex application where your state is needed in many parts of the DOM tree. You would reach a point in your app where it would become really hard for you to track down the value and bugs that are being passed down through props.
So this is where Context comes in to save us. So in order to use context react gives us a hook called useContext
. (Context can also be used with class-based components but we are going to cover the hooks part only.)
Using useContext
- React gives us an API
createContext
. This returns a Context object and our components can subscribe to this returned context object and consume those values that exist in this context. - Now we would code the previous example where we tried accessing the
userName
inside Profile without context.
// UsernameContext.js
import { createContext } from "react";
const UsernameContext = createContext();
export default UsernameContext;
- Above we used createContext API and made this UsernameContext that would hold the username for our app. (You can pass initial values right here in createContext as well).
// index.js
import UsernameContext from "./UsernameContext";
const intialValues = { userName: "Mr. Ferb" };
ReactDOM.render(
<StrictMode>
<UsernameContext.Provider value={intialValues}>
<App />
</UsernameContext.Provider>
</StrictMode>,
rootElement
);
- Here we used
Provider
of UsernameContext object that would make the values of this context available to children components. In this case, the children component is<App />
. -
UsernameContext.Provider
expects value prop.
// Profile.js
import UsernameContext from "./UsernameContext";
export default function Profile() {
const { userName } = useContext(UsernameContext);
return (
<div>
<h1>Welcome {userName} </h1>
</div>
);
}
- Now to consume values of
UsernameContext
, we would useuseContext
hook. We pass the Context object here that we want to use. In our case we want to useUsernameContext
object.
Note - There are cleaner ways of writing context like taking Context.Provider
out of index.js
but I left them as it is for simplicity's purpose.
Did you see that when we used context we no longer had to touch the <App />
and <Dashboard />
components? The values came down without having to pass from App/Dashboard. This is the power of context.😎😎😎
Woohoo, now we know why does context exist in react? and how to use it?
Some things to point about context -
- Whenever value prop changes in provider, react causes rerender to each consumer components of that respective context.
- If the provider sits at root component then changes in provider causes the whole app to rerender.
- You don't have any means of preventing the rerender cause on every prop change each component subscribed to context is forced to rerender.
Now coming to the title of article - Are you using context right?
So this question because people usually say Can we use context+useReducer
instead of redux
? To understand this question let's go back to definition of context by react -
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
If you read carefully it clearly says that context helps to
pass
the data? Right? It never said that context manages state. But when you use termredux
it means that you're referring to state management.Speaking of state management, we can say that useState/useReducer does manipulate our state. So they are sort of state management but context never manages your state. It just passes it down the DOM.
You can think of context as conveyer belt where you put something(some values) on it and then that belt keeps rolling. Whenever those things(values) reach desired station(component where you want to use values), you take them off the belt.
In the whole process, context never stores and manipulates the values.
So how does redux differ in this scenario?
Redux also uses context for availing redux store instances to components in DOM tree.
But in redux, your components can subscribe to part of the whole store and they would only rerender when those values change but this is not the case in context.
So this feature of redux helps us improve the performance of web apps by controlling the rerender that would happen in-app.
So it really depends on what is the need of your app. If your app performs frequent updates then using context with useReducer might yield some performance issues in your app. But if you want control over your component updates then redux is the way to go. We got to understand that context wasn't supposed to be used as state management.
So with this, we've reached the end of the article. I would like to put a statement here that I came across when I was reading this blog by Mark Erikson. Sebastian Markbage(React Core Team) said this about Context -
My personal summary is that new context is ready to be used for low frequency unlikely updates (like locale/theme). It's also good to use it in the same way as old context was used. I.e. for static values and then propagate updates through subscriptions. It's not ready to be used as a replacement for all Flux-like state propagation.
Thank you if you read till here! 👋
Top comments (0)