Another approach (different than the general passing props answer) you can use the Provider Pattern to share state to nested child components.
The Provider Pattern solves the problem of prop drilling. It uses React's Context API and the compound components pattern. The Provider pattern allows sharing state anywhere in the tree without drilling props to child components by exposing the React's Context.Consumer to child components.
Think of compound components like the <select> and <option> elements in HTML; the parent component acts as a wrapper to all child components where the parent component (provider component) manages shared state while the child components (consumer components) can access and update the shared state.
The Context API has 3 key parts:
const ToggleContext = React.createContext({
on: false,
toggle: () => {},
reset: () => {},
getTogglerProps: () => {}
});
class Toggle extends React.Component {
// Consumer, a static property
// We are not exposing the entire ToggleContext object to the user
// and we can use the component consumer directly off the Toggle Component
static Consumer = ToggleContext.Consumer;
//....
render() {
// Now we'll be exposing the state and helpers via React's context API.
const { children } = this.props;
// Using both the provider pattern and render props pattern
const ui = typeof children === "function" ? children(this.state) : children;
return (
<ToggleContext.Provider value={this.state}>{ui}</ToggleContext.Provider>
);
}
}
function NavSwitch() {
return (
<div className="nav-switch">
<Toggle.Consumer>
{toggle => (
<Switch
{...toggle.getTogglerProps({
on: toggle.on
})}
/>
)}
</Toggle.Consumer>
</div>
);
}
function Text() {
return (
<Toggle.Consumer>
{toggle => (toggle.on ? "️️On" : "Off")}
</Toggle.Consumer>
);
}
function App() {
return (
<div className="App">
<Toggle>
<div>
<Header />
<Text />
</div>
</Toggle>
</div>
);
}