反应挂钩useLayoutEffect不更新初始渲染时的ref参数

时间:2019-03-25 14:55:02

标签: reactjs

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

我知道使用useLayoutEffect代替useEffect应该同步触发。另外,也许问题出在ref本身,但是useRef不应该这样做吗?

Here's a sandbox with the full code

这是组成部分:

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: {contrast}</h1>,但我得到的一切都是null(因为默认情况下它是用useRef定义的。)

1 个答案:

答案 0 :(得分:2)

ref.current将在给useLayoutEffect的函数中设置,但不会在它之前设置,因此您不能执行if (!!ref.current) { ... }来有条件地使用该挂钩。您根本不应将钩子放在条件逻辑中。

这将按您期望的方式工作,因为在给浏览器绘画之前,useLayoutEffect赋予的函数内部发生的状态更新将被同步刷新。

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

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

    setContrast(contrast);
  });

  return contrast;
}