使用 React Hooks 响应 Native onLayout

React Native onLayout with React Hooks

我想在每次渲染时测量React Native View的大小,并将其保存到state。如果元素布局没有改变,效果应该不会 运行。

使用基于 class 的组件很容易做到,其中可以使用 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];
};

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

const [ref, dimensions] = useDimensions();

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

我试过调试 ref.current 但没有找到任何有用的东西。我也试过 measure() inside the effect hook:

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

您的想法是正确的,它只需要进行一些调整...主要是提交元素引用并在 useEffect 依赖项数组中使用 elementRef(不是 elementRef.current)。

(关于 useEffectuseLayoutEffect,因为你只是测量而不是改变 DOM 那么我相信 useEffect is the way to go,但是你如果需要可以换掉 like-for-like)

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 Native 版本:

对于 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>
    );

}

如果您想要一个更独立的版本,这里是 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} />;
};

作为对 ,并回答 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} />;
};