使用 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
)。
(关于 useEffect
与 useLayoutEffect
,因为你只是测量而不是改变 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>
);
}
编辑以添加 React Native 版本:
对于 React Native,您可以像这样使用 useState
和 onLayout
:
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} />;
};
我想在每次渲染时测量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
)。
(关于 useEffect
与 useLayoutEffect
,因为你只是测量而不是改变 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>
);
}
编辑以添加 React Native 版本:
对于 React Native,您可以像这样使用 useState
和 onLayout
:
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} />;
};
作为对
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} />;
};