React's useContext Hook

Not since the introduction of promises to Javascript has there been a principal that's as confusing yet as useful as React's useContext

What do I?

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

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>

useContext

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>
    )
}

TL;DR

  1. Create a context with createContext()

  2. Put your state variables in your root component

  3. Wrap your children components in a <MyContext.Provider value={{ my, state, variables}}>

  4. Access your variables in the child component using useContext (which returns an {} rather than [])