-
Notifications
You must be signed in to change notification settings - Fork 174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updating state with onViewableItemsChanged makes scrolling extremely laggy #160
Comments
We are experiencing the exact same issue, which indeed causes a janky experience. Let me know if I can assist to get this progressing. |
@bekatd try using a side-effect-free |
@PedroBern Thanks for the quick response, but it is not clear for me, can you elaborate on this? :) |
How can I get this value |
I think you misunderstood my goal. I am not trying to animate flatlist scrolling, but want to make video start/stop based on their positions, but I can't use |
Forget about it. Probably would be a big workaround. Why do you need this? Maybe what you need is to listen to the scrollY position... it's an open issue #156 |
No, but thanks. I already found workaround using refs instead of states and scrolling is now smooth again |
@bekatd Can you share your workaround? I can reproduce the issue with a simple setup like so:
|
Sure give me some time |
hope it helps To explain what happens here, we just store references to every flatlist item and |
@samih7 Did you manage to solve the problem? |
@bekatd Thanks for your answer, but not really. I gave it a try, my use case is exactly the same as yours (auto-playing videos when in view) but using a ref doesn't completely solve the issue – I still get some jumps when scrolling, whereas it's smoother with a normal Here is a basic example of how I implemented your approach, please tell me if I'm missing something: const ListItem = React.forwardRef(({ item, index }, ref) => {
const [isInView, setIsInView] = React.useState(false);
React.useImperativeHandle(ref, () => ({
setVisible: (inView) => {
setIsInView(inView);
},
}));
return (
<View
style={{
height: 100 + index * 10,
alignItems: 'center',
justifyContent: 'center',
borderBottomColor: 'red',
borderBottomWidth: 1,
}}
>
<Text>{item.id}</Text>
<Text>In view: {isInView ? 'YES' : 'NO'}</Text>
</View>
);
});
const List = () => {
const refs = React.useRef({});
const onViewableItemsChanged = React.useRef(({ changed }) => {
changed.forEach((item) => {
refs.current[item.item.id].setVisible(item.isViewable);
});
});
return (
<Tabs.FlatList
keyExtractor={(item) => item.id}
onViewableItemsChanged={onViewableItemsChanged.current}
viewabilityConfig={{ viewAreaCoveragePercentThreshold: 75 }}
data={items}
renderItem={({ item, index }) => (
<ListItem
item={item}
index={index}
ref={(ref) => {
refs.current[item.id] = ref;
}}
/>
)}
/>
);
}; |
Hey, sorry for late response. This is how I implemented refs and it works really smooth. Please copy this code and modify it import React, { useRef } from 'react';
import { Tabs } from 'react-native-collapsible-tab-view';
const TabOne = ({ data, ...rest }) => {
const refs = useRef({});
const onViewableItemsChanged = useRef(({ changed }) => {
changed.forEach((item) => {
refs.current[item.item.id]?.setVisible(item.isViewable);
});
});
return (
<Tabs.FlatList
data={data}
keyExtractor={(_, index) => index.toString()}
renderItem={({ item }) => (
<ListItem ref={(ref) => (refs.current[item.id] = ref)} />
)}
viewabilityConfig={{ viewAreaCoveragePercentThreshold: 75 }}
onViewableItemsChanged={onViewableItemsChanged.current}
{...rest}
/>
);
};
export default TabOne; PS: please make sure you do not force state updates somewhere else, which could trigger flatlist rerender. |
@newmanz12, about @samih7's code. I doubt it would work (unfortunately not able to test now), since he did not pass correct |
Got it. I'm having trouble understanding what you did in ListItem to get your code to run in terms of defining setVisible. Can you post yours? Included my code below. Currently not working. refs.current[item.item.id] is coming back as undefined. Console logged both refs.current and item.item.id which are coming back with values. However, not able to combine them together import React, {useState, useEffect, useRef, useMemo, useCallback} from "react";
import {View, FlatList, StatusBar, Dimensions, Text} from 'react-native'
import Post from '../../components/Post'
import SearchResultsMap from '../../screens/SearchResultsMap'
import Global from '../../components/Global'
import {useNavigation} from '@react-navigation/native';
const HomeDisplay = (props) => {
const { posts, users } = props;
const snapToInterval = useMemo(() => Dimensions.get('window').height + StatusBar.currentHeight-48, []);
const refs = useRef();
const onViewableItemsChanged = useRef(({ changed }) => {
changed.forEach((item) => {
refs.current[item.item.id]?.setVisible(item.isViewable);
});
});
return(
<View>
<FlatList
ref={refs}
data = {posts}
keyExtractor={(item) => item.id}
renderItem={({item, index}) => <Post post={item} ref={(ref) => (refs.current[item.id] = ref)} user = {users} index ={index} />}
showsVerticalScrollIndicator ={false}
snapToInterval ={snapToInterval}
snapToAlignment ={"start"}
decelrationRate={"fast"}
viewabilityConfig={{viewAreaCoveragePercentThreshold: 25,}}
onViewableItemsChanged={onViewableItemsChanged.current}
/>
</View>
)
}
export default HomeDisplay;
//Post Page below
import React, {useEffect, useState, useImperativeHandle} from 'react';
import{View, Text, TouchableWithoutFeedback, StatusBar, Image, TouchableOpacity, Pressable} from 'react-native';
import Video from 'react-native-video'
const Post = (props) =>
{
const [paused, setPaused] = useState(false)
const [muted, setMuted] = useState(false)
const [isInView, setIsInView] = useState(false);
useImperativeHandle(props.ref, () => ({
setVisible: (inView) => {
setIsInView(inView);
},
}));
//Deleted lots of code as unnecessary for the example
return(
//Deleted lots of code as unnecessary for the example
<View >
<Video
source = {{ uri: videoUri}}
style = {styles.video}
onError = {(e) => console.log(e)}
resizeMode ={'cover'}
repeat = {true}
paused = {!(isInView) || paused}
muted = {!(isInView) || muted}
/>
</View>
)
}
export default Post; |
@newmanz12 please indent your code when pasting here, to ensure markup. And please post minimal code and using my code example above and let me know if it works |
Closing this since it seems it was caused by excessive re-renders and not a library issue. |
@andreialecu I think it's a library issue, since it doesn't occur with a normal |
Definitely library issue. In my opinion internal state updates or references cause some excessive number of adjustments (maybe scrolling position calculations) and when adding even more functionality or state updates, multiple concurrent things happen. Like, vissualy jumping scroll back and forth means that some timing function causes it, which is used internally by lib. Anyway great lib, but this issue needs resolve, since its one of the mostly use case in my opinion |
Alright, PRs welcome. The code for |
@andreialecu The lag problem is caused by the Something in that logic is causing excessive re-renders when scrolling. When I leave out the |
I am trying to toggle tab flatlist item visibility prop on/off based on they are visible or not in current viewport via
onViewableItemsChanged
but seems like this lib does heavy computations and when updating state of flatlist (which rerenders all items) scrolling experience is extremely laggyCurrent behavior
Scrolling is buggy, items are jumping on every rerender up and down
Expected behaviour
Scrolling must remain smooth
Code sample
What have you tried
I tried to use standard
FlatList
instead ofTabs.FlatList
and scrolling issue gone, but the whole functionality of this lib is lost.The text was updated successfully, but these errors were encountered: