【问题标题】:Using useState hook in useEffect on history.listen在 history.listen 的 useEffect 中使用 useState 钩子
【发布时间】:2019-10-27 00:06:03
【问题描述】:

在收听history 更改useEffect 时,我遇到了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 使用 setStateflags 设置为 [],但随后使用 flags 添加回之前的状态。

我怎样才能删除所有flags,但记住当前state 用于其他items

【问题讨论】:

  • 你能提供一个codeandbox吗?
  • 您的GlobalProvider 似乎可以在pathname 更改及其默认状态之间被卸载。

标签: javascript reactjs typescript react-hooks


【解决方案1】:

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

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

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

【讨论】:

  • 历史应该是一个依赖
  • 虽然技术上是正确的,但历史对象永远不会改变,因此它们在检查从未发生过的事情方面没有优势
  • 上面的代码是否也卸载了history.listen?这不会发生在我这边。
  • 不,你需要从效果中返回一个卸载函数
  • 这里不需要return 吗?
【解决方案2】:

我们这样使用它:

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

【讨论】:

    【解决方案3】:

    如果我理解您的要求:

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

    嗯,这是不可能的,使用useState 并且您应该小心嵌套状态对象,因为对于较大的对象,克隆可能会变得昂贵。 也许这就是你在这里试图避免的事情

    即使您切换到useReducer,您最终仍会为该州传播道具。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      • 2021-10-24
      • 2020-10-11
      • 2021-08-18
      • 2021-12-01
      相关资源
      最近更新 更多