If you think about it, the top-down data flow is what gave react superpowers.
- You have more control over your data. No more early JS days where you sweep through heaps & loads of JS files and figure out what mutated your state.
- It’s easier to debug, as you know what is coming from where
But what if we are building a deeply nested app?
const App = () => {
return (
<div>
App Contents
<Toolbar theme={store.theme} />
</div>
);
};
const Toolbar = ({ theme }) => {
return (
<div>
<Button theme={theme} label="Button 1" />
<Button theme={theme} label="Button 2" />
</div>
);
};
const Button = ({ theme, label }) => {
return (
<button style={{ backgroundColor: theme === "dark" ? "black" : "white" }}>
{label}
</button>
);
};
This is called prop-drilling, and this gets even worse if you have more layers of components between the data source and user. How to solve this? React Context to the rescue!!
Solving prop drilling by using the Context API
The Context API lets you broadcast your state/data to multiple components by wrapping them with a context provider. Pass your state as value attribute to the contextProvider, the children components can then tap into this provider using a context consumer or the useContext Hook.
Step 1: Create Context
// ThemeContext.jsx
import React from "react";
const ThemeContext = React.createContext();
export default ThemeContext;
Step 2: Context Provider:
Now we can wrap all the context users with the Context Provider, and pass the value that we want to 'broadcast'.
const App = () => {
return (
<ThemeContext.Provider value={{ theme: store.theme }}>
App Contents
<Toolbar />
</ThemeContext.Provider>
);
};
Now, how do we access the theme from its descendants Toolbar, Button?
Step 3: Context Consumer: useContext
To access the context, we use useContext hook from any descendant of Component App
.
import React from "react";
import { ThemeContext } from "./ThemeContext";
const Button = ({ theme, label }) => {
const { theme } = React.useContext(ThemeContext);
return (
<button style={{ backgroundColor: theme === "dark" ? "black" : "white" }}>
{label}
</button>
);
};
Here, Our rendered output remains the same, but the code underneath is a bit leaner and cleaner.
That's all! I hope that I helped clarify why you need context and how to implement it. Feel free to post any questions, comments or any suggestions.
Top comments (0)