React对象是useEffect依赖项,会在每个渲染器上触发回调

时间:2020-07-16 11:02:03

标签: javascript reactjs react-hooks use-effect

我有一个相对简单的React钩子来反跳一个值。唯一的不足是,我想提供一个在去抖动值更改时触发的回调。我知道我可以在App内有另一个useEffect来监听debouncedValue上的更改,但我想将此行为集成到可重用的挂钩中。

const useDebounce = (value, delay, { onChange }) => {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const timeout = setTimeout(() => {
      setDebouncedValue(value);
      onChange(value);
    }, delay);

    return () => {
      clearTimeout(timeout);
    };
  }, [value, delay, onChange]);

  return debouncedValue;
};

const App = () => {
  const [value, setValue] = useState("");
  const debouncedValue = useDebounce(value, 750, { onChange: (value) => console.log(value) });

  return (
    <div style={{ margin: 50 }}>
      <input value={value} onChange={(event) => setValue(event.target.value)} />
      <p>{value}</p>
      <p>{debouncedValue}</p>
    </div>
  );
};

现在,我遇到的问题是onChange每次去抖动都会触发两次。显然,onChange回调必须是useEffect的依赖项数组的一部分,即使我不在乎它何时更新也是如此。但这产生了问题,而不是在每个渲染器上都为{ onChange: (value) => console.log(value) }创建一个新对象,因此引用相等性认为useEffect的依赖关系已更改。我可以在组件之外创建对象,但这也会使钩子的API复杂化。

所以,我的问题是:解决此问题的最简单方法是什么?理想情况下,无需拉入任何第三方包装。我可以想到的解决方法是编写一个自定义的useEffect挂钩,该挂钩可以进行深层比较,但我希望有人可以为我提供一个更简单的解决方案。

0 个答案:

没有答案