javascript - 在其他地方更新状态时未触发 useEffect 挂钩
问题描述
我在尝试收听此应用程序中的状态更改时遇到了一些问题。基本上,我期待在某些状态发生变化后触发 useEffect 挂钩,但什么都没有发生。
这就是我得到的
索引.jsx
// this is a simplification.
// I actually have a react-router-dom's Router wrapping everything
// and App is a Switch with multiple Route components
ReactDOM.render(
<Provider>
<App>
</Provider>
, document.getElementById('root'));
使用Session.jsx
export const useSession = () => {
const [session, setSession] = useState(null)
const login = useCallback(() => {
// do something
setSession(newSession)
})
return {
session,
setSession,
login
}
}
提供者.jsx
const { session } = useSession();
useEffect(() => {
console.log('Print this')
}, [session])
// more code ...
应用程序.jsx
export function Login() {
const { login } = useSession();
return <button type="button" onClick={() => { login() }}>Login</button>
}
好吧,我有这个父组件提供者监视会话状态,但是当它更新时,提供者的 useEffect 永远不会被调用。
useEffect
仅当在setSession
相同的钩子/方法中调用时才会触发。例如,如果我setSession
在 the 中导入并在其中Provider
使用它,useEffect
则将触发;或者,如果我useEffect
在useSession
方法中添加一个,它会在login
更新状态时被触发。
的回调useEffect
只被调用一次,当组件被挂载时,而不是在状态改变时。
我怎样才能实现这种行为?每次更新都会触发Provider
's吗?useEffect
session
提前致谢!
解决方案
我认为这只是对自定义钩子如何工作的一点误解。组件的每个实例都有自己的状态。让我举一个简单的例子来说明这一点。
function App () {
return (
<div>
<ComponentA/>
<ComponentB/>
<ComponentC/>
<ComponentD/>
</div>
)
}
function useCounter() {
const [counter, setCounter] = React.useState(0);
function increment() {
setCounter(counter+1)
}
return {
increment, counter, setCounter
}
}
function ComponentA() {
const { counter, increment }= useCounter()
return (
<div>
<button onClick={()=>increment()}>Button A</button>
ComponentA Counter: {counter}
</div>
)
}
function ComponentB() {
const { counter, increment }= useCounter()
return (
<div>
<button onClick={()=>increment()}>Button B</button>
ComponentB Counter: {counter}
</div>
)
}
function ComponentC() {
const { counter }= useCounter();
return (
<div>
ComponentC Counter: {counter}
</div>
)
}
function ComponentD() {
const [toggle, setToggle] = React.UseState(false);
const { counter }= useCounter();
React.useEffect(() => {
setInterval(()=>{
setToggle(prev => !prev);
}, 1000)
})
return (
<div>
ComponentD Counter: {counter}
</div>
)
}
从上面的代码中可以看出,通过点击增加countButton A
并不会影响count实例。ComponentB
这是因为组件的每个实例都有自己的状态。您还可以看到,单击任一按钮都不会触发ComponentC
重新渲染,因为它们不共享同一个实例。即使我像在组件 D 中那样每隔一秒触发一次重新渲染,因此调用useCounter
的计数器ComponentD
仍然为 0。
解决方案 然而,有多种方法可以让组件共享/监听相同的状态变化
- 您可以将所有状态(即 [会话状态])转移到
Provider
组件,并通过 props 传递它使其对其他组件可见。 - 您可以将状态移动到全局容器Redux或简单地使用Context Api + UseReducer Hook 这是一个示例
但是由于您正在处理身份验证和会话管理,我建议您将会话状态保存在本地存储或会话存储中,并在需要时检索它。希望有帮助
推荐阅读
- node.js - Chai/Mocha:尽管识别到 AssertionError,但我的测试不会抛出错误
- activemq - 运行 ActiveMQ 的服务器上的负载增加了很多
- c++ - C++实现二叉树
- c++ - 错误“启动:程序
在 ubuntu 中编写 c++ 的 vscode 中不存在” - node.js - 启动节点 js 服务器时显示警告消息:DeprecationWarning: A boolean value was passed to options
- silk-performer - Silk 执行器中的脚本问题
- asp.net-identity - ASP.NET Core 3.0 - 身份自定义问题
- angular - 发布新数据后,是否可以从 web api 角度获取当前 id 的值?
- java - 将 Arrays.sort() 用于非字母字符,例如 {'+' '1' 'D'}
- amazon-web-services - 是否可以使用/连接 AWS Cognito 用户池到 AWS SFTP 服务器访问