我有两个组件和一个上下文提供程序,当我在父级调用钩子时,我可以更改状态并让这两个组件通过上下文获取值
contex api用法的工作演示,但我在父级调用了change状态,这不是我想要的https://stackblitz.com/edit/react-51e2ky?file=index.js
我想用钩子来改变内部组件的状态,但是当我点击navbar login时,我看不到这个值被改变了。
https://stackblitz.com/edit/react-rgenmi?file=Navbar.js
父级:
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>
}自定义挂钩
const loginHook = () => {
const [user, setUser] = React.useState(null)
return {
user,
setUser
}
}我可以将setUser从父级传递到子级,但我希望避免这种情况,我希望可以无缝地使用上下文api和react钩子。
发布于 2020-05-19 17:43:40
目前,您只在上下文中设置user值,这就是获取正确值的原因。
然而,在您的Navbar.js组件中,您正在调用loginHook,它将创建该钩子的一个新“实例”,实际上具有其自己的状态。
我建议您在上下文中也添加update函数
const App = () => {
const {user, setUser} = loginHook()
return (
<UserContext.Provider value={{ user, setUser}}>
<Navbar />
<Content />
</UserContext.Provider>
);
}这样,您也可以访问您的孩子的setUser,例如
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的更多信息
发布于 2020-05-19 17:40:30
您不能从子项更改父项的上下文信息,不能。您需要从父进程向子进程传递一些内容,子进程可以使用这些内容让父进程知道上下文需要更新(比如父进程的setUser副本)。您可以通过一个道具或通过将setUser添加到上下文中来做到这一点,尽管我倾向于将其作为需要能够设置用户的组件的道具,而不是所有这些组件都可以访问的上下文。
在这两个地方使用loginHook都不起作用的原因是每个组件(App和Navbar)都有自己的user副本。这是钩子工作原理的基础。(如果它以某种方式使它们共享状态信息,useState将根本无法工作-所有状态将在所有组件之间共享。)丹·阿布拉莫夫的A Complete Guide to 可能是一本有帮助的读物(它更多地是关于钩子和组件的工作原理,而不是专门关于useEffect的)。
发布于 2020-05-19 17:48:51
你必须注意到自定义钩子不共享实例引用,所以如果你在应用程序中使用loginHook,在导航栏中使用另一个钩子,它们将创建两个独立的状态和更新器
现在,使用来自自定义钩子的setter将更新上下文中的状态。
您可以通过编写loginHook,使其在内部使用上下文,然后使用它来重新构造它
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
}
}现在有多种方法可以编写此代码,但是在上面的场景中,最好的方法是根本不使用自定义钩子,因为它无论如何都没有用
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>
}https://stackoverflow.com/questions/61887821
复制相似问题