Not since the introduction of promises to Javascript has there been a principal that's as confusing yet as useful as React's useContext
React useContext is a hook which helps you manage state across components. It's used when prop drill gets too deep, but you aren't "enterprise" enough to use a separate state manager.
Prop drilling is when you pass a prop down through several layers of components. This gets a little shifty as you start passing parameters through many levels of components - due to rerendering, and just overall code understandiblity.
const [someState, setSomeState] = useEffect()
<RootComponent>
{ someState }
<NextComponent1 someParameter={setSomeState}>
<NextComponent2 deeperParameter={props.someParameter}>
<NextComponent3 evenDeeper={props.deeperParameter}>
<NextComponent4>... you get it</NextComponent4>
</NextComponent3>
</NextComponent2>
<NextComponent1>
</RootComponent>
So the trick is to create a Context object which is wrapped around your top <RootContext> like component, and assign state variables which will be accessible to any of the child components.
// Define your context
//
// For example we'll define a context that makes
// username available to all child components
type UserContextType = {
userName: string
setUserName: (value: string) => void
}
// Now create the context object that ill be consumed by a child
// component
export const UserContext = createContext({} as UserContextType)
// Now define the state you want available at the top node
export default function ContextComponent() {
const [userName, setUserName] = useEffect() // These state variables will be available
// through the context object
return (
<RootComponent>
{ /* This state variable will be updated in a child component */}
{ userName }
{ /* Wrap your components with your context */}
<UserContext.Provider value={{ userName, setUserName}}>
<NextComponent1> {/* Notice no state being passed */}
<NextComponent2>
<NextComponent3>
<NextComponent4>
{ // Pretend this is defined in another component
const { userName, setUserName } = React.useContext<UserContextType>(UserContext)
}
<input value={ userName } onChange={ setUserName }>
</NextComponent4>
</NextComponent3>
</NextComponent2>
<NextComponent1>
</UserContext.Provider>
</RootComponent>
)
}
Create a context with createContext()
Put your state variables in your root component
Wrap your children components in a <MyContext.Provider value={{ my, state, variables}}>
Access your variables in the child component using useContext (which returns an {} rather than [])