使用React Hooks进行React Native onLayout

swe*_*edo 2 react-native react-hooks

我想在每次渲染时测量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];
};
Run Code Online (Sandbox Code Playgroud)

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

const [ref, dimensions] = useDimensions();

return (
  <View ref={ref}>
    ...
  </View>
);
Run Code Online (Sandbox Code Playgroud)

我尝试调试,ref.current但是没有找到有用的东西。我也在效果挂钩中尝试了measure()

ref.current.measure((size) => {
  setDimensions(size); // size is always 0
});
Run Code Online (Sandbox Code Playgroud)

mat*_*990 9

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

  • 很好,谢谢!我喜欢独立的自定义钩子,它允许我在使用它们的组件中做尽可能少的事情。 (3认同)

Jim*_*dan 6

作为对matto1990 答案的改进 ,并回答 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] = useComponentLayout();
  return <View onLayout={onLayout} />;
};
Run Code Online (Sandbox Code Playgroud)


Wil*_*ins 5

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

(关于useEffectvs useLayoutEffect,因为你只是在测量而不是改变 DOM 那么我相信这useEffect 是要走的路,但如果你需要,你可以像对一样交换它)

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];
};
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

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>
  );
}
Run Code Online (Sandbox Code Playgroud)

工作代码和框在这里

编辑添加 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>
    );

}
Run Code Online (Sandbox Code Playgroud)