[英]Using useState hook in useEffect on history.listen
I am having some troubles with useState
when listening to history
changes in useEffect
.在收听
useEffect
的history
变化时,我在使用useState
时遇到了一些问题。
When the pathname
changes, setState
is initiated but then the state
is added back.当
pathname
更改时,会启动setState
,但随后会添加回state
。
For example, I have a flag
component that collects groups of notifications, but on the pathname
change, I want all flags to be dismissed and removed from state
.例如,我有一个收集通知组的
flag
组件,但是在pathname
更改时,我希望所有标志都被解除并从state
中删除。
The flag component标志组件
const PageFlag = ({ history }: InterfaceProps) => {
const { contextData, dismissFlag, dismissAllFlags } = useContext(GlobalConsumer);
useEffect(() => {
history.listen(() => {
dismissAllFlags();
});
});
return (
<>
<FlagGroup onDismissed={dismissFlag}>
{contextData.flags.map((flag, index) => (
<Flag key={index} {...flag} />
))}
</FlagGroup>
</>
);
};
History prop is used from import { withRouter } from 'react-router-dom'
历史道具用于
import { withRouter } from 'react-router-dom'
The state and function for dismissAllFlags
is shown in a createContext
component as用于
dismissAllFlags
的 state 和 function 在createContext
组件中显示为
const DefaultState: InterfaceState = {
otherStateExample: false,
flags: []
};
export const GlobalConsumer = createContext({
contextData: DefaultState,
addFlag: (flagData: any) => {},
dismissFlag: () => {},
dismissAllFlags: () => {}
});
export const GlobalProvider = ({ children }: InterfaceProps) => {
const [state, setState] = useState<InterfaceState>({
...DefaultState
});
return (
<GlobalConsumer.Provider
value={{
contextData: state,
addFlag: (flagData: any) => {
setState({ ...state, flags: [flagData].concat(state.flags) });
},
dismissFlag: () => {
setState({ ...state, flags: state.flags.slice(1) });
},
dismissAllFlags: () => {
setState({ ...state, flags: [] });
}
}}
>
{children}
</GlobalConsumer.Provider>
);
};
The problem arises, where on pathname
change, dismissAllFlags
uses setState
to set flags
as []
but then adds back the previous state with the flags
.问题出现了,在
pathname
更改时, dismissAllFlags
使用setState
将flags
设置为[]
但随后将先前的 state 与flags
添加回来。
How can I remove all flags
but remember the current state
for other items
?如何删除所有
flags
但记住其他items
的当前state
?
You are missing the second input parameter on useEffect()
, which is going to cause the listener to be readded on every render.您缺少
useEffect()
上的第二个输入参数,这将导致在每次渲染时都读取侦听器。
It should look like this, note you also should not need the inner function.它应该看起来像这样,注意你也不应该需要内部 function。
useEffect(() => {
history.listen(dismissAllFlags)
}, []);
We use it like this:我们像这样使用它:
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
history.listen(() => setIsOpen(false));
}, [history]);
If I understand what your asking is this:如果我明白你的要求是这样的:
You would like to set the flags to an empty array without have to add the previous values using the spread method that you are currently doing
{...state, flags: []}
.您想将标志设置为空数组,而不必使用您当前正在执行的扩展方法添加先前的值
{...state, flags: []}
。
Well, this is not possible using useState
and you should be cautions with nested state objects as cloning can becoming expensive with larger objects.好吧,使用
useState
是不可能的,您应该注意嵌套的 state 对象,因为使用较大的对象进行克隆可能会变得昂贵。 Maybe that is what your trying to avoid here .也许这就是你在这里试图避免的。
Even if you switch to useReducer
you would still end up prop spreading for the state.即使您切换到
useReducer
,您最终仍会为 state 进行道具传播。
Perhaps you should just have flags as its own state const [flags, setFlags] = useState([])
or look into immutable-helper .也许您应该将标志作为自己的 state
const [flags, setFlags] = useState([])
或查看immutable-helper 。
Moreover, Try to respect react-hooks/exhaustive-deps
otherwives funny things can start happening.此外,尽量尊重
react-hooks/exhaustive-deps
otherwives 有趣的事情可能会开始发生。 If no deps then at least give your hook an empty array to ensure it is performed once.如果没有部门,那么至少给你的钩子一个空数组以确保它执行一次。
I tried to reproduce your problem on CodeSandbox, using your code.我尝试使用您的代码在 CodeSandbox 上重现您的问题。 But everything works fine.
但一切正常。
You can check it here:你可以在这里查看:
Possible problems:可能出现的问题:
addFlag
somewhere right after calling dismissAllFlags
.addFlag
之后立即在某处调用dismissAllFlags
。 I added commented line in the sandbox example.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.