【问题标题】:Change state conditioned on in useEffect without triggering the hook and without breaking the exhaustive dependencies rule以 useEffect 为条件更改状态而不触发钩子并且不破坏穷举依赖规则
【发布时间】:2020-03-02 21:31:09
【问题描述】:

我正在尝试在 useEffect 挂钩中将突变注册为 inFlight。仅当尚未注册突变时才应进行注册。因此,我在状态中有一个布尔变量来跟踪突变是否已经被注册,并且我根据它有条件地注册。在我在 useEffect 中注册突变后,我立即将此变量设置为 true。因此,我在执行注销后立即在我的注销突变函数中将其设置为 false。

问题来了:为了遵守 useEffect 的详尽依赖规则,我必须在依赖数组中包含布尔状态变量。但是,这意味着一旦我取消注册,useEffect 就会运行并重新注册突变。相反,我希望取消注册只是“准备”注册,然后仅在特定值更改后才进行注册。在遵守穷举依赖规则的情况下,这是否可能?

我尝试将布尔变量更改为包含三种状态(AwaitingValueChange、ShouldDispatch、HasDispatched)的 ENUM,仅在其值为 ShouldDispatch 时调度,并在注销时将该值设置为 AwaitingValueChange。然后我创建了一个新的钩子,每次触发注册的值更改时都会运行它,如果当前值为 AwaitingValueChange,则将状态变量设置为 ShouldDispatch。然而,新的钩子也以状态变量为条件,所以我遇到了完全相同的问题,只是这次调用链是:取消注册 -> 新钩子 -> 旧钩子 -> 注册而不是取消注册 -> 旧钩子-> 注册。

注册码:

useEffect(() => {
  if (hasRegisteredMutationInFlight && inFlightDispatch) {
        inFlightDispatch({ type: 'registerMutation', mutationName });
        setHasRegisteredMutationInFlight(true);
      }
  }, [hasRegisteredMutationInFlight, ...]);

注销代码:

const deregisterMutation = () => {
  inFlightDispatch({ type: 'deregisterMutation', mutationName });
  setHasRegisteredMutationInFlight(false);
};

我想要某种方式来设置状态,而不是让它触发我的 useEffect,而是使用该状态在同一个 useEffect 中有条件地执行操作。我也不想打破详尽的依赖规则。对我来说,目前的 useEffect 实现听起来不可能,但我希望这里有人比我聪明一点,并且可以看到一些我忽略的解决方案

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    您不能对registerderegister 突变使用相同的标志。这根本没有意义。为什么在deregisterMutation 中需要setHasRegisteredMutationInFlight (false)?您可以取消注册,然后在重新注册某个值时将标志设置为 false,这样它就不会依赖于相同的值。只是我的意思的一个工作示例

    您也可以让我知道您要满足的具体用例,以便我可以为您提供更多帮助

    import React, { useEffect, useCallback, useState } from "react";
    import ReactDOM from "react-dom";
    
    const mutationName = "MUTATION_NAME";
    
    function App() {
      const [type, setType] = useState("");
      const [isMutationSet, setMutationToRegister] = useState(true);
      const inFlightDispatch = useCallback(
        stuff => {
          setType(stuff.type);
        },
        [setType]
      );
    
      useEffect(() => {
        if (isMutationSet && inFlightDispatch) {
          inFlightDispatch({ type: "registerMutation", mutationName });
          setMutationToRegister(false);
        }
      }, [isMutationSet, inFlightDispatch]);
    
      const deregisterMutation = () => {
        inFlightDispatch({ type: "deregisterMutation", mutationName });
      };
    
      const registerMutation = () => {
        setMutationToRegister(true);
      };
    
      return (
        <div className="App">
          {type}
          <button onClick={deregisterMutation}>Degister</button>
          <button onClick={registerMutation}>Register</button>
        </div>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    
    

    【讨论】:

    • 感谢您的回答。不幸的是,它不适用于我的用例。我正在构建一个保存为用户类型的表单。由于每次值更改时都会调用我的寄存器函数,因此我需要该标志以防止在第一次用户输入和(去抖动)突变完成之间的时间内多次调用它。此外,上述代码位于自定义钩子中,并且将注销函数返回给组件。该标志是组件与变更完成的钩子通信的方式,因此必须在取消注册中设置
    猜你喜欢
    • 2019-11-20
    • 2020-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多