当我在useEffect
中听到history
的更改时,useState
遇到了一些问题。
当pathname
改变时,setState
被启动,但随后state
被添加回来。
例如,我有一个flag
组件,它收集通知组,但在pathname
更改时,我希望从state
中消除所有标志。
标志组件
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>
</>
);
};
从import { withRouter } from 'react-router-dom'
使用历史道具
dismissAllFlags
的状态和功能在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>
);
};
出现的问题是,在pathname
更改时,dismissAllFlags
使用setState
将flags
设置为[]
,但随后使用flags
将先前的状态添加回来。
如何删除所有flags
,但记住其他items
的当前state
?
useEffect()
上缺少第二个输入参数,这将导致侦听器在每次渲染时都被读取。
它应该是这样的,注意你也不应该需要内部功能。
useEffect(() => {
history.listen(dismissAllFlags)
}, []);
我们这样使用它:
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
history.listen(() => setIsOpen(false));
}, [history]);
如果我理解你的要求:
您希望将标志设置为空数组,而不必使用当前正在执行
{...state, flags: []}
的排列方法添加以前的值。
好吧,使用useState
是不可能做到这一点的,对于嵌套状态对象应该小心,因为对于较大的对象,克隆可能会变得昂贵也许这就是你在这里试图避免的。
即使你切换到useReducer
,你最终仍然会支持该州的传播。
也许您应该将标志作为自己的状态const [flags, setFlags] = useState([])
,或者查看不可变的助手。
此外,试着尊重react-hooks/exhaustive-deps
其他妻子有趣的事情可能会开始发生。如果没有deps,那么至少给你的钩子一个空数组,以确保它执行一次。