从两个不同的useEffect调用方法(改变状态)

时间:2019-09-17 18:27:09

标签: javascript reactjs react-hooks

我正在玩React Hooks,从两个不同的useEffect调用一个方法(改变状态)。给出以下代码:

function App() {
  const [clicked, setClicked] = useState(false);

  /**
   * Listen for clicked changes. When clicked changes to true,
   * allow setCounterAndSetUrlHash to do it's thing, before accpeting
   * the next click. So the clicked flag is simply a valve, that opens
   * after two seconds.
   */
  useEffect(() => {
    if (clicked) {
      setCounterAndSetUrlHash(counter + 1);
      setTimeout(() => {
        setClicked(false);
      }, 2000);
    }
  }, [clicked]);

  const [counter, setCounter] = useState(0);

  /**
   * Listen for changes in the URL hash. When the user presses
   * the back button in the browser toolbar, decrement the
   * counter value.
   */
  useEffect(() => {
    window.onhashchange = () => {
      const value = Number(window.location.hash.replace("#", ""));
      // must be number
      if (typeof value === "number" && value % 1 === 0) {
        if (counter - 1 === value) {
          setCounterAndSetUrlHash(counter - 1);
        }
      }
    };
  });

  /**
   * Set a new counter value and apply the same value
   * to the URL hash. I want to reuse this function
   * in both useEffect above.
   */
  const setCounterAndSetUrlHash = value => {
    setCounter(value);
    if (value === 0) {
      window.location.hash = "";
    } else {
      window.location.hash = String(value);
    }
  };

  return (
    <div className="App">
      <p>Clicked: {String(clicked)}</p>
      <p>Counter: {counter}</p>
      <button type="button" onClick={() => setClicked(true)}>
        Click me
      </button>
    </div>
  );
}

正在执行的代码:https://codesandbox.io/s/dreamy-shadow-7xesm

该代码实际上正在工作。但是我收到此警告。

  

React Hook useEffect缺少依赖项:“计数器”。要么   包括它或删除依赖项数组。   (反应钩/详尽的下降)

..而且我不确定在保持当前功能的情况下如何与之保持一致。当我添加计数器依赖项时,最终会出现无限循环。

4 个答案:

答案 0 :(得分:1)

您的第一个效果使用counter状态变量,但其依赖项列表不包含它。将其包含在依赖项列表中将创建无限循环。

您可以使用counter中的函数类型参数来删除对setCounter的依赖。

function App() {
  const [clicked, setClicked] = useState(false);

  /**
   * Listen for clicked changes. When clicked changes to true,
   * allow setCounterAndSetUrlHash to do it's thing, before accpeting
   * the next click. So the clicked flag is simply a valve, that opens
   * after two seconds.
   */
  useEffect(() => {
    if (clicked) {
      incrCounter(1);
      setTimeout(() => {
        setClicked(false);
      }, 2000);
    }
  }, [clicked]);

  const [counter, setCounter] = useState(0);

  /**
   * Listen for changes in the URL hash. When the user presses
   * the back button in the browser toolbar, decrement the
   * counter value.
   */
  useEffect(() => {
    window.onhashchange = () => {
      const value = Number(window.location.hash.replace("#", ""));
      // must be number
      if (typeof value === "number" && value % 1 === 0) {
        if (counter - 1 === value) {
          incrCounter(- 1);
        }
      }
    };
  });

  useEffect(() => {
    if (counter === 0) {
      window.location.hash = "";
    } else {
      window.location.hash = String(counter);
    }
  }, [counter])
  /**
   * Set a new counter value and apply the same value
   * to the URL hash. I want to reuse this function
   * in both useEffect above.
   */
  const incrCounter = delta => {
    setCounter(value => value + delta);
  };

  return (
    <div className="App">
      <p>Clicked: {String(clicked)}</p>
      <p>Counter: {counter}</p>
      <button type="button" onClick={() => setClicked(true)}>
        Click me
      </button>
    </div>
  );
}

答案 1 :(得分:1)

尝试使用功能性setState setState((state, props) => stateChange)

useEffect(() => {
  if (clicked) {
    setCounterAndSetUrlHash(counter => counter + 1);
    setTimeout(() => {
      setClicked(false);
    }, 2000);
  }
}, [clicked]);

答案 2 :(得分:0)

要使用第一个计数器值解决$validatedData = $request->validate([ 'titulo' => 'required|max:255', 'start' => 'required|max:255', 'starttime' => 'required|max:255', <---- 'end' => 'required|max:255', 'endtime' => 'required|max:255', <---- 'descripcion' => 'required|max:255', 'color' => 'required|max:255', ]); $Calendarios=Calendarios::create($validatedData); 回调的问题,我建议将功能移至onhashchange的回调。这也意味着按钮和哈希更改需要不同的功能。

还要在顶部和setCounter之后设置变量和useState定义,以便可以使用它们。如果只想让useEffect运行一次,请设置一个空的依赖项数组;消除依赖关系将在每个渲染器上运行。

useEffect

答案 3 :(得分:0)

为第一个useEffect()添加计数器:

  const [counter, setCounter] = useState(0);

  useEffect(() => {
    if (clicked) {
      setCounterAndSetUrlHash(counter + 1);
      setTimeout(() => {
        setClicked(false);
      }, 2000);
    }
  }, [clicked, counter]);

https://codesandbox.io/s/cold-sun-56u7j