繁体   English   中英

在 history.listen 的 useEffect 中使用 useState 钩子

[英]Using useState hook in useEffect on history.listen

在收听useEffecthistory变化时,我在使用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的 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>
  );
};

问题出现了,在pathname更改时, dismissAllFlags使用setStateflags设置为[]但随后将先前的 state 与flags添加回来。

如何删除所有flags但记住其他items的当前state

您缺少useEffect()上的第二个输入参数,这将导致在每次渲染时都读取侦听器。

它应该看起来像这样,注意你也不应该需要内部 function。

useEffect(() => {
  history.listen(dismissAllFlags)
}, []);

我们像这样使用它:

const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
    history.listen(() => setIsOpen(false));
  }, [history]);

如果我明白你的要求是这样的:

您想将标志设置为空数组,而不必使用您当前正在执行的扩展方法添加先前的值{...state, flags: []}

好吧,使用useState是不可能的,您应该注意嵌套的 state 对象,因为使用较大的对象进行克隆可能会变得昂贵。 也许这就是你在这里试图避免的

即使您切换到useReducer ,您最终仍会为 state 进行道具传播。

也许您应该将标志作为自己的 state const [flags, setFlags] = useState([])或查看immutable-helper

此外,尽量尊重react-hooks/exhaustive-deps otherwives 有趣的事情可能会开始发生。 如果没有部门,那么至少给你的钩子一个空数组以确保它执行一次。

我尝试使用您的代码在 CodeSandbox 上重现您的问题。 但一切正常。

你可以在这里查看:

编辑居高临下的kapitsa-l2j4i

可能出现的问题:

  • 可能是您在调用addFlag之后立即在某处调用dismissAllFlags 我在沙盒示例中添加了注释行。 使用这一行,代码就像您在问题中描述的那样工作。
  • 另一个版本的依赖项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM