React钩子useLayoutEffect在初始渲染时未更新ref参数

6

我正在尝试运行一个函数,检查任何DOM节点与其背景的对比度,并将节点本身的引用作为参数传递。但在初始渲染时,引用值保持null,我不明白为什么。

我理解使用useLayoutEffect而非useEffect应该会同步触发。另外,问题可能出在引用本身上,但是useRef不应该能解决这个问题吗?

这里有完整代码的沙盒

这是组件部分:

function App() {
  const ref = useRef(null);
  const contrast = useContrast(ref);

  return (
    <div className="App">
      <h1 ref={ref}>Contrast: {contrast}</h1>
    </div>
  );
}

还有自定义钩子部分:

export default function useContrast(ref) {
  const [contrast, setContrast] = useState("");

  if (!!ref.current) {
    useLayoutEffect(() => {
      const contrast = contrastValidation(
        getForegroundColor(ref.current),
        getBackgroundColor(ref.current)
      );

      setContrast(contrast);
    });
    return ref.current;
  }

  return contrast;
}

这里应该显示一些对比度值:<h1 ref={ref}>对比度:{contrast}</h1>,但是我得到的都是null(因为它默认使用了useRef)。

1个回答

7

ref.current将在给useLayoutEffect函数的内部设置,但它不会在此之前设置,因此您不能进行if (!!ref.current) { ... }条件性地使用hook。您根本不应该在条件逻辑中放置hooks。

执行这个操作会如您所预期的工作,因为在给useLayoutEffect函数的内部发生的状态更新将在浏览器有机会绘制之前同步刷新。

export default function useContrast(ref) {
  const [contrast, setContrast] = useState("");

  useLayoutEffect(() => {
    const contrast = contrastValidation(
      getForegroundColor(ref.current),
      getBackgroundColor(ref.current)
    );

    setContrast(contrast);
  });

  return contrast;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接