使用React挂钩在布局上进行React本机操作

ht4b089n  于 2023-03-03  发布在  React
关注(0)|答案(3)|浏览(132)

我想在每次渲染React Native View时测量它的大小,并将其保存到状态。如果元素布局没有更改,效果将不会运行。
使用基于类的组件很容易,可以使用onLayout,但是在使用React Hooks的函数组件中我该怎么做呢?
我读过关于useLayoutEffect的文章。如果这就是你要做的,你有一个如何使用它的例子吗?
我做了一个叫做useDimensions的自定义钩子。这是我目前的进展:

const useDimensions = () => {
  const ref = useRef(null);
  const [dimensions, setDimensions] = useState({});
  useLayoutEffect(
    () => {
      setDimensions(/* Get size of element here? How? */);
    },
    [ref.current],
  );
  return [ref, dimensions];
};

然后我使用钩子,将ref添加到我想要测量尺寸的视图中。

const [ref, dimensions] = useDimensions();

return (
  <View ref={ref}>
    ...
  </View>
);

我试过调试ref.current,但没有发现任何有用的东西,我也试过在effect钩子内使用measure():

ref.current.measure((size) => {
  setDimensions(size); // size is always 0
});
jv2fixgn

jv2fixgn1#

如果你想要一个更加独立的版本,这里是一个React Native的定制钩子版本:

const useComponentSize = () => {
  const [size, setSize] = useState(null);

  const onLayout = useCallback(event => {
    const { width, height } = event.nativeEvent.layout;
    setSize({ width, height });
  }, []);

  return [size, onLayout];
};

const Component = () => {
  const [size, onLayout] = useComponentSize();
  return <View onLayout={onLayout} />;
};
j8ag8udp

j8ag8udp2#

您的想法是正确的,它只需要一些调整...主要是,在useEffect依赖项数组中提交元素ref并使用elementRef(而不是elementRef.current)。
(关于useEffectuseLayoutEffect,因为您只是在测量而不是改变DOM,所以我认为useEffectis the way to go是正确的,但是如果需要,您可以将其互换)

const useDimensions = elementRef => {
   const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
   useEffect(() => {
      const el = elementRef.current;
      setDimensions({ width: el.clientWidth, height: el.clientHeight });
    }, [elementRef]);
    return [dimensions];
};

像这样使用它:

function App() {
  const divRef = useRef(null);
  const [dimensions] = useDimensions(divRef);
  return (
    <div ref={divRef} className="App">
      <div>
        width: {dimensions.width}, height: {dimensions.height}
      </div>
    </div>
  );
}

Working codesandbox here

已编辑以添加React本机版本:

对于React Native,您可以将useStateonLayout一起使用,如下所示:

const App=()=>{
  const [dimensions, setDimensions] = useState({width:0, height:0})
    return (
      <View onLayout={(event) => {
                const {x, y, width, height} = event.nativeEvent.layout;
                setDimensions({width:width, height:height});
        }}>
        <Text}>
          height: {dimensions.height} width: {dimensions.width}
        </Text>
      </View>
    );

}
sg3maiej

sg3maiej3#

作为matto1990's answer的一个改进,为了回答Kerkness的问题,下面是一个提供x,y位置和布局大小的自定义钩子示例:

const useComponentLayout = () => {
  const [layout, setLayout] = React.useState(null);

  const onLayout = React.useCallback(event => {
    const layout = event.nativeEvent.layout;
    setLayout(layout);
  }, [])

  return [layout, onLayout]
}

const Component = () => {
  const [{ height, width, x, y }, onLayout] = useComponentSize();
  return <View onLayout={onLayout} />;
};

相关问题