React 钩子缺少自定义钩子的依赖性 setter

React hook missing dependency of custom hook setter

我很清楚 Hook has missing dependency 是什么,它意味着什么以及为什么观察所有依赖项很重要,但是这个很奇怪。

export function Compo() {
  const [value, setValue] = useState<number>();

  useEffect(() => {
    setValue(Date.now());
  }, []);

  return (
    <>{value}</>
  );
}

工作正常,但是:

function useValue() {
  return useState<number>();
}

export function Compo() {
  const [value, setValue] = useValue();

  useEffect(() => {
    setValue(Date.now());
  }, []);

  return (
    <>{value}</>
  );
}

显示众所周知的React Hook useEffect has a missing dependency: 'setValue'. Either include it or remove the dependency array react-hooks/exhaustive-deps

您在示例中注意到的是规则 react-hooks/exhaustive-deps 的一个怪癖。它为它知道的挂钩提供特殊特权,并且知道在某些情况下是“稳定的”。

引用实现:

// Next we'll define a few helpers that helps us
// tell if some values don't have to be declared as deps.

// Some are known to be stable based on Hook calls.
// const [state, setState] = useState() / React.useState()
//               ^^^ true for this reference
// const [state, dispatch] = useReducer() / React.useReducer()
//               ^^^ true for this reference
// const ref = useRef()
//       ^^^ true for this reference
// False for everything else.

来源:https://github.com/facebook/react/blob/v17.0.1/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js#L152

具体来说,this part of the rule 似乎是在这些情况下免除 useState 钩子的 setter 的原因:

if (name === 'useState') {
  const references = resolved.references;
  for (let i = 0; i < references.length; i++) {
    setStateCallSites.set(
      references[i].identifier,
      id.elements[0],
    );
  }
}
// Setter is stable.
return true;

挂钩 helpfuln/clever 的不幸结果是它可能导致其推理不起作用的混乱,就像您刚才描述的场景一样。