Home > OS >  React Context Provider not setting value
React Context Provider not setting value

Time:04-15

I am trying to get started with React context hooks and I seem to be having an issue I dont understand.

I have defined a user context that is simply a string that says "hello user" as such:

import { useContext, createContext } from "react"

export const UserContext = createContext<string | null>(null)

export interface IAuth {
  children: React.ReactNode;
}

const Auth: React.FC<IAuth> = (props) => {

  return(
    <UserContext.Provider value={"hello user"}>
      {props.children}
    </UserContext.Provider>
  )
}

export default Auth

Then I am attempting to access is like this:

const Dash: NextPage<dashPageProps> = (props) => {

  const contextMsg = useContext(UserContext)

  const submitForm = () => {
    console.log("logout")
  }

  return (
    <Auth>
    <div className="w-screen">
      <div className='text-xl'>
        Dashboard
      </div>
      <h1>{contextMsg}</h1>
      <button className='bg-gray-400 border-2 border-gray-600 w-fit mt-5' onClick={submitForm} >Log out</button>
    </div>
    </Auth>
  )
}

export default Dash

But nothing is being printed out even though I have set a value when using UserContext.Provider. It will have a value if I specify one when creating the context but not when I set it through the provider.

What am I doing wrong here?

CodePudding user response:

Your Auth is called within the component but you call useContext before Auth usage which means your Context API has not been initialized yet

In the usual components, you can initialize them with a component wrapper like

<Context.Provider>
  <YourComponent/> // you call `useContext` in `YourComponent`
</Context.Provider>

But in Next.js, especially, under a page-level component, it's not a good way to construct multiple Context APIs due to clean code concerns

I'd suggest you should move your Auth to _app.tsx like below that would help you initialize your Context API before all page-level components' renderings

export default function MyApp(props: AppProps) {
  const { Component, pageProps } = props

  return (
    <React.Fragment>
      <Auth>
        <Component {...pageProps} />
      </Auth>
    </React.Fragment>
  )
}

Dash.tsx

const Dash: NextPage<dashPageProps> = (props) => {

  const contextMsg = useContext(UserContext)

  const submitForm = () => {
    console.log("logout")
  }

  return (
    <div className="w-screen">
      <div className='text-xl'>
        Dashboard
      </div>
      <h1>{contextMsg}</h1>
      <button className='bg-gray-400 border-2 border-gray-600 w-fit mt-5' onClick={submitForm} >Log out</button>
    </div>
  )
}

export default Dash

CodePudding user response:

You cannot useContext outside its Provider.

You will need to move your Auth component up a level so that it surrounds Dash in order to make use of const contextMsg = useContext(UserContext)

In the end your React Component Tree should look like this:

<Auth>
  <Dash />
</Auth>
  • Related