useRef Div 宽度更改时更新 UI

11 reactjs

我有一个useRef附加到一个div。当 div 的宽度发生变化时,我需要更新我的 UI。我可以使用 访问它ref.current.innerWidth,但是,当它的宽度发生变化时,它不会更新依赖于 的其他元素ref.current.innerWidth

我怎样才能做到这一点?

代码:

let ref = useRef();

return (
  <>
    <Box resizable ref={ref}>
      This is a resizable div
    </Box>

    <Box width={ref.current.innerWidth}>
      This box needs the same with as the resizable div
    </Box>
  </>
);
Run Code Online (Sandbox Code Playgroud)

fre*_*edy 11

您可以使用 ResizeObserver。像这样实现,每次 ref 的大小发生变化时,它都会设置宽度:

let ref = useRef()

const [width, setwidth] = useState(0)

useEffect(() => {
  const observer = new ResizeObserver(entries => {
    setwidth(entries[0].contentRect.width)
  })
  observer.observe(ref.current)
  return () => ref.current && observer.unobserve(ref.current)
}, [])

return (
  <>
    <Box ref={ref}>
      This is a resizable div
    </Box>

    <Box width={width}>
      This box needs the same with as the resizable div
    </Box>
  </>
)

Run Code Online (Sandbox Code Playgroud)

  • 如果您正在考虑对特定元素大小调整(而不是整个视口)做出反应,这是最干净的方法。 (2认同)

Ely*_*755 5

对于任何寻求可重用逻辑和Typescript支持的人,我根据@fredy的精彩答案创建了以下自定义挂钩,并修复了我在他的答案中发现的一些问题:

import { useState, useRef, useEffect } from "react";


export const useObserveElementWidth = <T extends HTMLElement>() => {
    const [width, setWidth] = useState(0);
    const ref = useRef<T>(null);

    useEffect(() => {
        const observer = new ResizeObserver((entries) => {
            setWidth(entries[0].contentRect.width);
        });

        if (ref.current) {
            observer.observe(ref.current);
        }

        return () => {
            ref.current && observer.unobserve(ref.current);
        };
    }, []);

    return {
        width,
        ref
    };
};
Run Code Online (Sandbox Code Playgroud)

然后,导入useObserveElementWidth并使用它,如下所示:

const YourComponent = () => {
  const { width, ref } = useObserveElementWidth<HTMLDivElement>();

  return (
    <>
      <Box resizable ref={ref}>
        This is a resizable div
      </Box>

      <Box width={width}>
        This box needs the same with as the resizable div
      </Box>
    </>
  );
};
Run Code Online (Sandbox Code Playgroud)

我为它创建了一个示例codesandbox。


b3h*_*r4d 3

您应该使用 useEffect 和 useState 以及窗口上的事件监听器创建生命周期来监听数据更改,然后基于该更改重新渲染组件。

代码沙盒

  const [size, setSize] = useState(null);
  let ref = useRef();

  const updateDimensions = () => {
    console.log(ref.current.clientWidth);
    if (ref.current) setSize(ref.current.clientWidth);
  };

  useEffect(() => {
    window.addEventListener("resize", updateDimensions);
    setSize(ref.current.clientWidth);
    return () => {
      console.log("dismount");
      window.removeEventListener("resize", updateDimensions);
    };
  }, []);

  return (
    <>
      <div ref={ref}>This is a resizable div</div>

      <div
        style={{
          width: size,
          border: "1px solid"
        }}
      >
        This div needs the same with as the resizable div
      </div>
    </>
  );
Run Code Online (Sandbox Code Playgroud)