Context allows us to pass data through the component tree without relying on props every time (often referred to as ‘broadcasting’ data). Implementing context is useful for when we need many components at different nesting levels to have access to the same data (ex: UI theme, locale preference, current user) or in other words, when we need data to be considered ‘global’.
Implementing Context
The following code breakdown is inspired from the UI theme use-case example provided by the React documentation.
To use and update context, first we would need to define our theme object from which we will be pulling the context values from.
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
Then we need to use React.createContext
to create a context for theme with a default value. In the code example below, we’re using the themes.dark
object as our default value.
const ThemeContext = React.createContext(themes.dark)
We then need to use .Provider
to provide an updated value for the specific context.
function App() {
return (
//provide the theme context's value to change/update the previous theme context's value
<ThemeContext.Provider value={themes.light}>
<Navigation />
</ThemeContext.Provider>
)
}
To access our theme context value, we can use the useContext(SpecifiedContext)
hook. useContext(ThemeContext)
accepts our ThemeContext
context variable in the format of an object (the returned object value from React.createContext
) and it returns the current context value for the specific context. We can save this returned context value to a variable in order to use it in our code.
function ThemedButton() {
// save theme context value to theme variable
const theme = useContext(ThemeContext)
return (
// use theme variable to manipulate button styling
<button style={{ background: theme.background, color: theme.foreground }} >
My styling comes from theme context!!!
</button>
)
function Navigation() {
// return our ThemedButton component to display our ThemeButton
return <ThemedButton />
}
The current context value is determined by the value prop of the nearest SpecifiedContext.Provider
above the calling component in the tree. When the nearest SpecifiedContext.Provider
above the component updates, the useContext hook will trigger a re-render with the updated latest context value.
Implementing Containment
Something to consider is that context makes component reuse harder. So, if we need to simply avoid the prop code redundancy of passing props through unnecessary intermediate levels, we should consider using the children
prop within component composition. Component composition is React’s original development model of using either explicitly defined props or using implicit children props to pass down JSX components or elements via containment.
children
is a special prop that passes implicit children elements directly into a component’s output via nesting within the parent component.
function ChildComponent(props) {
return (
<div>
{props.children}
</div>
)
}
function ParentComponent() {
return (
<ChildComponent>
<h1>I am the first child prop!</h1>
<h2>I am the second child prop!</h2>
</ChildComponent>
)
}
We can make our own custom convention if we’re needing to use a more specific children-prop-breakdown.
function ChildComponent(props) {
return (
<div>
<div>{props.left}</div>
<div>{props.right}</div>
</div>
)
}
function ParentComponent() {
return (
<ChildComponent>
left={<LeftChildComponent />}
right={<RightChildComponent />}
</ChildComponent>
)
}
Containment is useful because we can pass down entire components or JSX elements down as props instead of passing down props through intermediate components.
To read more on composition, feel free to refer to the React documentation on the topic.
TLDR:
Containment can be used for most use cases when we simply need to decouple a child from its immediate parent (so that we don’t have so much redundancy in passing down props within intermediate relationships). Usually, this means that children and parent components have a singular nesting pattern.
Context, on the other hand, is useful for ‘broadcasting’ our data - accessing data by many components at different nesting levels.
Top comments (0)