Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

hook change state doesn't update context provider's value?

I have 2 component, and a context provider, when I call my hook at parent level, I have no issue changing the state and having those 2 component getting the value via context

working demo of contex api usage but I call change state at parent level which is not what I wanted https://stackblitz.com/edit/react-51e2ky?file=index.js

I want to change state at inner component with hook, but I don't see the value been changed when I click on the navbar login.

https://stackblitz.com/edit/react-rgenmi?file=Navbar.js

parent:

const App = () => {
  const {user} = loginHook()
    return (
      <UserContext.Provider value={user}>
        <Navbar />
        <Content />
      </UserContext.Provider>
    );

}

Navbar.js

const Navbar = () => {
  const user = React.useContext(userContex)
  const {setUser} = loginHook()

  return <div>{user ? <span>{user.name}</span> : <button onClick={() => {
    setUser({
      name: 'jane'
    })
  }}>navbar Login</button>}</div>
}

custom hook

const loginHook = () => {
  const [user, setUser] = React.useState(null)

  return {
    user,
    setUser
  }
}

I can pass setUser from parent to children but I want to avoid that, I expect I can use context api and react hook seamlessly.

like image 405
Andre Thonas Avatar asked Nov 07 '22 07:11

Andre Thonas


1 Answers

Currently, you're only setting the user value in the context, which is why getting the correct value will work.

However, in your Navbar.js component, you are making a call to loginHook, which will create a new "instance" of that hook, effectively having its own state.

I suggest you add the update function in your context as well, as such

const App = () => {
  const {user, setUser} = loginHook()
    return (
      <UserContext.Provider value={{ user, setUser}}>
        <Navbar />
        <Content />
      </UserContext.Provider>
    );

}

That way you can access the setUser in your children as well, e.g.

const Navbar = () => {
  const {user, setUser} = React.useContext(userContex)

  return <div>{user ? <span>{user.name}</span> : <button onClick={() => {
    setUser({
      name: 'jane'
    })
  }}>navbar Login</button>}</div>
}

Also, small note: it's best to start you custom hook with use, as that's a best-practice when writing your own hooks.

Important caveat however, this is not really a good practice. If your user were to change, all components that are only listening to setUser will also get an update an thus do a useless rerender. You can solve this by using two different contexts, one for the value, and one for the updater. You can read more about this here

like image 72
JDansercoer Avatar answered Nov 14 '22 02:11

JDansercoer