首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >钩子更改状态不会更新上下文提供程序的值吗?

问钩子更改状态不会更新上下文提供程序的值吗?
EN

Stack Overflow用户
提问于 2020-05-19 17:36:51
回答 4查看 1.9K关注 0票数 5

我有两个组件和一个上下文提供程序,当我在父级调用钩子时,我可以更改状态并让这两个组件通过上下文获取值

contex api用法的工作演示,但我在父级调用了change状态,这不是我想要的https://stackblitz.com/edit/react-51e2ky?file=index.js

我想用钩子来改变内部组件的状态,但是当我点击navbar login时,我看不到这个值被改变了。

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

父级:

代码语言:javascript
复制
const App = () => {
  const {user} = loginHook()
    return (
      <UserContext.Provider value={user}>
        <Navbar />
        <Content />
      </UserContext.Provider>
    );

}

Navbar.js

代码语言:javascript
复制
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>
}

自定义挂钩

代码语言:javascript
复制
const loginHook = () => {
  const [user, setUser] = React.useState(null)

  return {
    user,
    setUser
  }
}

我可以将setUser从父级传递到子级,但我希望避免这种情况,我希望可以无缝地使用上下文api和react钩子。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2020-05-19 17:43:40

目前,您只在上下文中设置user值,这就是获取正确值的原因。

然而,在您的Navbar.js组件中,您正在调用loginHook,它将创建该钩子的一个新“实例”,实际上具有其自己的状态。

我建议您在上下文中也添加update函数

代码语言:javascript
复制
const App = () => {
  const {user, setUser} = loginHook()
    return (
      <UserContext.Provider value={{ user, setUser}}>
        <Navbar />
        <Content />
      </UserContext.Provider>
    );

}

这样,您也可以访问您的孩子的setUser,例如

代码语言:javascript
复制
const Navbar = () => {
  const {user, setUser} = React.useContext(userContex)

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

另外,小提示:最好从use开始定制钩子,因为这是编写您自己的钩子时的最佳实践。

但重要的是,这并不是一个好的实践。如果你的user改变了,所有只监听setUser的组件也会得到更新,从而导致一个无用的重新渲染。您可以通过使用两个不同的上下文来解决这个问题,一个用于值,另一个用于更新程序。您可以阅读有关此here的更多信息

票数 2
EN

Stack Overflow用户

发布于 2020-05-19 17:40:30

您不能从子项更改父项的上下文信息,不能。您需要从父进程向子进程传递一些内容,子进程可以使用这些内容让父进程知道上下文需要更新(比如父进程的setUser副本)。您可以通过一个道具或通过将setUser添加到上下文中来做到这一点,尽管我倾向于将其作为需要能够设置用户的组件的道具,而不是所有这些组件都可以访问的上下文。

在这两个地方使用loginHook都不起作用的原因是每个组件(App和Navbar)都有自己的user副本。这是钩子工作原理的基础。(如果它以某种方式使它们共享状态信息,useState将根本无法工作-所有状态将在所有组件之间共享。)丹·阿布拉莫夫的A Complete Guide to 可能是一本有帮助的读物(它更多地是关于钩子和组件的工作原理,而不是专门关于useEffect的)。

票数 0
EN

Stack Overflow用户

发布于 2020-05-19 17:48:51

你必须注意到自定义钩子不共享实例引用,所以如果你在应用程序中使用loginHook,在导航栏中使用另一个钩子,它们将创建两个独立的状态和更新器

现在,使用来自自定义钩子的setter将更新上下文中的状态。

您可以通过编写loginHook,使其在内部使用上下文,然后使用它来重新构造它

代码语言:javascript
复制
const App = () => {
  const [user, setUser] = useState();
    return (
      <UserContext.Provider value={{user, setUser}}>
        <Navbar />
        <Content />
      </UserContext.Provider>
    );

}

const Navbar = () => {
  const {user, setUser} = loginHook();

  return <div>{user ? <span>{user.name}</span> : <button onClick={() => {
    setUser({
      name: 'jane'
    })
  }}>navbar Login</button>}</div>
}
const loginHook = () => {
  const {user, setUser} = React.useContext(UserContext)

  return {
    user,
    setUser
  }
}

现在有多种方法可以编写此代码,但是在上面的场景中,最好的方法是根本不使用自定义钩子,因为它无论如何都没有用

代码语言:javascript
复制
const App = () => {
  const [user, setUser] = useState();
    return (
      <UserContext.Provider value={{user, setUser}}>
        <Navbar />
        <Content />
      </UserContext.Provider>
    );

}

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

  return <div>{user ? <span>{user.name}</span> : <button onClick={() => {
    setUser({
      name: 'jane'
    })
  }}>navbar Login</button>}</div>
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61887821

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档