【问题标题】:React Native onLayout with React HooksReact Native onLayout 与 React Hooks
【发布时间】:2019-11-06 08:59:18
【问题描述】:

我想在每次渲染时测量 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,但没有发现任何有用的东西。我还在效果挂钩中尝试了measure()

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

【问题讨论】:

    标签: react-native react-hooks


    【解决方案1】:

    如果你喜欢这个更独立的版本,这里是 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} />;
    };
    

    【讨论】:

    • 很好,谢谢!我喜欢独立的自定义钩子,它允许我在使用它们的组件中做尽可能少的事情。
    • 这是一个很棒的钩子。无论如何也可以获得x和y位置吗?
    • 我下面的答案也有一个获得职位的例子:stackoverflow.com/a/63859317/1547857
    【解决方案2】:

    你的想法是对的,它只需要一些调整...主要是提交元素 ref 并在 useEffect 依赖数组中使用 elementRef(不是 elementRef.current)。

    (关于useEffect vs useLayoutEffect,因为你只是在测量而不是改变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 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 中做到这一点?
    【解决方案3】:

    作为改进 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} />;
    };
    

    【讨论】:

      猜你喜欢
      • 2020-01-17
      • 2019-11-08
      • 2019-01-18
      • 1970-01-01
      • 2020-11-19
      • 2019-10-17
      • 2020-07-08
      • 2021-01-29
      • 1970-01-01
      相关资源
      最近更新 更多