[英]useEffect hook not triggered when state is updated somewhere else
I`m having some problems trying to listen to state changes in this application.我在尝试收听此应用程序中的 state 更改时遇到了一些问题。 Basically I was expecting a useEffect hook to be fired after some state changed, but nothing at all is happening.基本上我期待在一些 state 改变后会触发一个 useEffect 钩子,但什么都没有发生。
This is what I got这就是我得到的
index.jsx索引.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'));
useSession.jsx使用Session.jsx
export const useSession = () => {
const [session, setSession] = useState(null)
const login = useCallback(() => {
// do something
setSession(newSession)
})
return {
session,
setSession,
login
}
}
Provider.jsx提供者.jsx
const { session } = useSession();
useEffect(() => {
console.log('Print this')
}, [session])
// more code ...
App.jsx应用程序.jsx
export function Login() {
const { login } = useSession();
return <button type="button" onClick={() => { login() }}>Login</button>
}
Well I have this Parent component Provider watching the session state, but when it is updated the useEffect of the provider is never called.好吧,我有这个父组件 Provider 正在监视 session state,但是当它更新时,永远不会调用提供者的 useEffect。
The useEffect
is fired only if the setSession
is called in the same hook/method.仅当setSession
在相同的钩子/方法中调用时才会触发useEffect
。 For example, if I import the setSession
in the Provider
and use it there, the useEffect
will be fired;例如,如果我在Provider
中导入setSession
并在那里使用它,则将触发useEffect
; Or if I add a useEffect
in the useSession
method, it is gonna be fired when login
updates the state.或者,如果我在useSession
方法中添加一个useEffect
,它将在login
更新 state 时被触发。
The callback of useEffect
is called but only once, when the component is mounted, but not when the state is changed. useEffect
的回调只被调用一次,当组件被挂载时,而不是当 state 被改变时。
How can I achieve this behavior?我怎样才能实现这种行为? Having the Provider
's useEffect
fired whenever session
is updated?每次更新session
时都会触发Provider
的useEffect
吗?
Thanks in advance!提前致谢!
I think this is just a bit of misunderstanding of how custom hooks work.Every instance of the component has its own state.我认为这只是对自定义钩子如何工作的一点误解。组件的每个实例都有自己的 state。 Let me just show a simple example illustrating this.让我举一个简单的例子来说明这一点。
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>
)
}
From the above code if you can see that incrementing count by clicking Button A
will not affect the count instance of ComponentB
.This is because every instance of the component has its own state .从上面的代码中可以看出,点击Button A
增加计数不会影响ComponentB
的计数实例。这是因为组件的每个实例都有自己的 state 。 You can also see that clicking either buttons won't trigger ComponentC
to rerender since they don't share the same instance.您还可以看到,单击任一按钮都不会触发ComponentC
重新呈现,因为它们不共享相同的实例。 Even if i trigger rerender every one second like in Component D thus invoking useCounter
the counter in ComponentD
remains 0.即使我像在组件 D 中那样每隔一秒触发一次重新渲染,从而调用useCounter
, ComponentD
D 中的计数器仍然为 0。
Solution However there are multiple ways of making components share/listen to same state changes解决方案然而,有多种方法可以让组件共享/监听相同的 state 更改
Provider
component and make it visible to other components by passing it via props.您可以将所有 state 即 [会话状态] 转移到Provider
组件,并通过道具传递它使其对其他组件可见。But since you are dealing with auth and session management, I suggest you persist the session state in local storage or session storage, and retrieve it whenever you need it. But since you are dealing with auth and session management, I suggest you persist the session state in local storage or session storage, and retrieve it whenever you need it. Hope that helped希望有帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.