我在尝试监听此应用程序中的状态更改时遇到一些问题。基本上,我期望在某些状态更改后会触发useEffect挂钩,但是什么也没有发生。
这就是我所得到的
index.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
export const useSession = () => {
const [session, setSession] = useState(null)
const login = useCallback(() => {
// do something
setSession(newSession)
})
return {
session,
setSession,
login
}
}
Provider.jsx
const { session } = useSession();
useEffect(() => {
console.log('Print this')
}, [session])
// more code ...
App.jsx
export function Login() {
const { login } = useSession();
return <button type="button" onClick={() => { login() }}>Login</button>
}
我让这个Parent组件Provider监视会话状态,但是当它更新时,永远不会调用该提供者的useEffect。
只有在相同的挂钩/方法中调用useEffect
时才会触发setSession
。例如,如果我将setSession
导入Provider
并在其中使用,则会触发useEffect
;或者,如果我在useEffect
方法中添加useSession
,则login
更新状态时将触发它。
useEffect
的回调仅在安装组件时被调用一次,而在状态改变时仅被调用。
如何实现此行为?每当Provider
更新时是否触发useEffect
的{{1}}?
谢谢!
答案 0 :(得分:1)
我认为这只是对自定义钩子工作方式的误解。每个组件实例都有其自己的状态。让我只显示一个简单的例子来说明这一点。
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>
)
}
从上面的代码中,如果您可以看到通过单击Button A
来增加计数不会影响ComponentB
的计数实例。这是因为 该组件的每个实例都有其自己的状态 。您还可以看到单击任何一个按钮都不会触发ComponentC
,因为它们不共享同一实例。即使我像组件D中那样每秒触发一次重新渲染,从而调用useCounter
,ComponentD
中的计数器仍为0。
解决方案 但是,有多种方法可以使组件共享/监听相同的状态更改
Provider
组件,并通过道具将其传递给其他组件。但是,由于您要处理身份验证和会话管理,因此建议您将会话状态保留在本地存储或会话存储中,并在需要时将其检索。希望有帮助