【问题标题】:Confusion about the inputs array of useEffect(React Hooks API)关于 useEffect 的输入数组的困惑(React Hooks API)
【发布时间】:2019-01-09 02:50:21
【问题描述】:

useEffectuseMemouseCallback 等一些 React Hooks API 有第二个参数:输入数组:

useEffect(didUpdate, inputs);

正如官方文档所说:

@见Conditionally firing an effect

  1. 这样,如果其中一个输入发生变化,总是会重新创建效果。

  2. 在效果函数中引用的每个值也应该出现在输入数组中。

所以我们可以看到,inputs 数组有两个职责。 在大多数情况下,它们工作正常。但有时它们会发生冲突。

例如,我有一个小程序,它做了两件事:

  1. 点击按钮,计数加1。

  2. 每 5 秒将计数发送到服务器。

代码沙盒:

https://codesandbox.io/s/k0m1mq9v

或者在这里查看代码:

import { useState, useEffect, useCallback } from 'react';

function xhr(count) {
  console.log(`Sending "${count}" to my server.`);
  // TODO send count to my server by XMLHttpRequest
}

function add1(n) {
  return n + 1;
}

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  // Handle click to increase count by 1
  const handleClick = useCallback(
    () => setCount(add1),
    [],
  );

  // Send count to server every 5 seconds
  useEffect(() => {
    const intervalId = setInterval(() => xhr(count), 5000);
    return () => clearInterval(intervalId);
  }, []);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={handleClick}>
        Click me
      </button>
    </div>
  );
}

export default Example;

当我运行这段代码时,我总是将count = 0 发送到我的服务器,因为我还没有将count 传递给useEffect

但是如果我将count 传递给useEffect,我的setInterval 将被清除,并且每次单击按钮时都会重新创建整个回调。

我认为也许还有另一种范式来实现我没有想到的目标。如果不是,那就是inputs数组的冲突。

【问题讨论】:

  • 你这里的场景绝对是有效的,虽然我发现它相当特定于 setInterval 函数的特性,也许还有 limitation 只能从 React 函数调用钩子。
  • @ClaireLin setInterval 只是一个例子。 WebSocketsetTimeoutaddEventListenerXMLHttpRequest等,他们都有同样的问题。

标签: javascript reactjs react-hooks


【解决方案1】:

React 的回复:

React discussion Github

可能会实施更好的解决方案,但不是现在。

但生活将继续,所以像this 这样的解决方法可能会有所帮助:

const [count, setCount] = useState(0);
const countRef = useRef(count);
useEffect(() => {
  countRef.current = count
}, [count]);

【讨论】:

    【解决方案2】:

    useRef() 可以解决你的问题。我认为这是一个优雅的解决方案:code in sandbox

    function App() {
      const [count, setCount] = useState(0);
    
      // ***** Initialize countRef.current with count
      const countRef = useRef(count);
    
      const handleClick = useCallback(() => setCount(add1), []);
    
      // ***** Set countRef.current to current count
      // after comment https://github.com/facebook/react/issues/14543#issuecomment-452996829
      useEffect(() => (countRef.current = count));
    
      useEffect(() => {
        // ***** countRef.current is xhr function argument
        const intervalId = setInterval(() => xhr(countRef.current), 5000);
        return () => clearInterval(intervalId);
      }, []);
    
      return (
        <div>
          <p>You clicked {count} times</p>
          <button onClick={handleClick}>Click me</button>
        </div>
      );
    }
    

    编辑

    评论后:https://github.com/facebook/react/issues/14543#issuecomment-452996829

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 2013-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-26
      相关资源
      最近更新 更多