useEffect 挂钩在其他地方更新状态时未触发
useEffect hook not triggered when state is updated somewhere else
我在尝试侦听此应用程序中的状态变化时遇到了一些问题。基本上我期待在某些状态更改后触发 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>
}
好吧,我有这个父组件提供者监视会话状态,但是当它更新时,提供者的 useEffect 永远不会被调用。
仅当 setSession
在同一个 hook/method 中被调用时才会触发 useEffect
。例如,如果我在 Provider
中导入 setSession
并在那里使用它,那么 useEffect
将被触发;或者,如果我在 useSession
方法中添加一个 useEffect
,它会在 login
更新状态时触发。
useEffect
的回调仅在安装组件时调用一次,但在状态更改时不会调用。
我怎样才能实现这种行为?是否在更新 session
时触发 Provider
的 useEffect
?
提前致谢!
我认为这只是对组件的自定义挂钩 work.Every 实例如何拥有自己的状态的一点误解。让我举一个简单的例子来说明这一点。
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
的计数实例。这是因为 every组件的实例有自己的状态。您还可以看到,单击任一按钮都不会触发 ComponentC
重新呈现,因为它们不共享同一个实例。即使我像在组件 D 中那样每隔一秒触发一次重新渲染,从而调用 useCounter
,ComponentD
中的计数器仍然为 0。
解决方案
然而,有多种方法可以使组件 share/listen 更改为相同的状态
- 您可以将所有状态(即 [会话状态])转移到
Provider
组件,并通过 props 传递它使其对其他组件可见。
- 您可以将状态移动到全局容器 Redux 或者简单地使用 Context Api + UseReducer 钩子 here is an example
但由于您正在处理身份验证和会话管理,我建议您将会话状态保存在本地存储或会话存储中,并在需要时检索它。希望有所帮助
我在尝试侦听此应用程序中的状态变化时遇到了一些问题。基本上我期待在某些状态更改后触发 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>
}
好吧,我有这个父组件提供者监视会话状态,但是当它更新时,提供者的 useEffect 永远不会被调用。
仅当 setSession
在同一个 hook/method 中被调用时才会触发 useEffect
。例如,如果我在 Provider
中导入 setSession
并在那里使用它,那么 useEffect
将被触发;或者,如果我在 useSession
方法中添加一个 useEffect
,它会在 login
更新状态时触发。
useEffect
的回调仅在安装组件时调用一次,但在状态更改时不会调用。
我怎样才能实现这种行为?是否在更新 session
时触发 Provider
的 useEffect
?
提前致谢!
我认为这只是对组件的自定义挂钩 work.Every 实例如何拥有自己的状态的一点误解。让我举一个简单的例子来说明这一点。
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
的计数实例。这是因为 every组件的实例有自己的状态。您还可以看到,单击任一按钮都不会触发 ComponentC
重新呈现,因为它们不共享同一个实例。即使我像在组件 D 中那样每隔一秒触发一次重新渲染,从而调用 useCounter
,ComponentD
中的计数器仍然为 0。
解决方案 然而,有多种方法可以使组件 share/listen 更改为相同的状态
- 您可以将所有状态(即 [会话状态])转移到
Provider
组件,并通过 props 传递它使其对其他组件可见。 - 您可以将状态移动到全局容器 Redux 或者简单地使用 Context Api + UseReducer 钩子 here is an example
但由于您正在处理身份验证和会话管理,我建议您将会话状态保存在本地存储或会话存储中,并在需要时检索它。希望有所帮助