Reputation: 59
I have a FlatList, and I'm trying to get each item's x, y, width, height
to do some animations. I've seen it's possible with .measure
and maybe even useRef
, but I'm not sure how to do it within FlatList's renderItem
since I can't use hooks within it.
function MyComponent() {
const renderItem = React.useCallback(
({ item, index }) => {
const coords = // ! How can I get these?
return (
<View key={item.id} style={containerStyle}>
<TouchableOpacity>
<Image
source={{ uri: item.uri }}
style={memoizedStyles.media}
/>
</TouchableOpacity>
</View>
);
},
[],
);
return (
<FlatList
data={myData}
numColumns={numColumns}
renderItem={renderItem}
/>
);
}
}
I'm not sure if a scrollable FlatList adds complexity here. Maybe it's best to measure onPress
or something? Regardless, some help would be great, thanks!
Upvotes: 1
Views: 950
Reputation: 3179
You're correct that you can't use hooks directly in the renderItem
callback there, but you can create your own wrapper component and call that instead:
const Item = ({ item }) =>
{
return (
<View key={item.id} style={containerStyle}>
<TouchableOpacity>
<Image
source={{ uri: item.uri }}
style={memoizedStyles.media}
/>
</TouchableOpacity>
</View>
);
};
...
const renderItem = React.useCallback(({ item, index }) => <Item item={item} />);
...
So far as getting the item size is concerned, you can certainly do this using useRef
and ref.measure(...)
but as the React Native docs note, you can get results sooner and slightly more easily using the onLayout
prop.
const Item = ({ item }) =>
{
const [coords, setCoords] = useState();
return (
<View key={item.id} style={containerStyle}
onLayout={ e => setCoords(e.nativeEvent.layout) }>
...
coords
will initially be undefined, but as soon as each Item
renders/re-renders coords
will contain {x,y,left,top,width,height}
.
EDIT 1
So – the x
and y
values are relative to each item's View container and not super useful for you, sorry!
Looks like react-native-web also provides left
and top
values in the LayoutEvent
that are not available on other platforms. So, we should use .measure(..)
instead:
const Item = ({ item }) =>
{
const [coords, setCoords] = useState();
const ref = useRef();
useEffect(() =>
ref.current.measure(
(x, y, width, height, pageX, pageY) =>
setCoords({ width, height, pageX, pageY })
),
[ref,setCoords]);
return (
<View key={item.id} style={containerStyle} ref={ref}>
...
This gives pageX
/pageY
– the absolute coordinates on the page.
There's also the measureLayout()
function which can give you coordinates relative to another component.
Upvotes: 2