Prevent Flatlist from scrolling when new items are added - react-native

When adding data to the Flatlist (e.g. subscriptions) it scrolls down leading to a very bad UX.
Any idea on how this could be solved?

Actually, I think this must be handled in native level, but not handled yet,
I solve my problem by saving scroll offset and set it again after reloading data like this:
reloadData(flatListData){
this.setState({
flatListData: flatListData
});
requestAnimationFrame(() => {
this.flatList.scrollToOffset({
animated: false,
offset: this.flatListLastOffset
});
});
}
...
<FlatList
data={this.state.flatListData}
ref={ref => this.flatList = ref}
onScroll={(event: Object) => {
this.flatListLastOffset = event.nativeEvent.contentOffset.y;
}}
horizontal={false}
scrollEventThrottle={16}
/>
this is not the best solution, but can fix my problem for now

Related

how can we autoscroll and autoloop flatlist in react native

I want my Flatlist autoscroll and loop in horizontal direction, please help me out
Thanks in Advance
<FlatList
style={{marginEnd:5}}
timer={2000}
// width={deviceWidth}
loop={true}
// keyExtractor={this._keyExtractor.bind(this)}
horizontal={true}
onScrollToIndexFailed={info => {
const wait = new Promise(resolve => setTimeout(resolve, 500));
wait.then(() => {
flatListFeaturedMobiles.current?.scrollToIndex({ index: info.index, animated: true });
});
}}
// onScrollToIndexFailed={()=>{}}
flatListRef={React.createRef()}
ref={this.flatListFeaturedMobiles}
autoscroll={true}
showsHorizontalScrollIndicator={false}
data={this.state.featuredMobiles}
horizontal
You can scroll the list using Animated like check it How do I make a list (FlatList) automatically scroll
You can also use react-native-autoscroll-flatlist#readme
For more detail you can read here wants-to-autoscroll-flatlist-in-react-native

Programmatically set scroll index of react native VirtualizedList

I have a book reader application, I implement book content thorough react native Virtuallist. In some case it needs to scroll to some titles in the book that can be out of screen and not rendered yet. If I load whole book's content I faced some performance issue. I need a way to change Virtuallist index or shift it on paragraph selection. this is what I implemented so far but it scroll to bottom constantly to render paragraph I chose, And looks so ugly.
const getItem = (_, index, focusedRank) => {
return data[index];
};
return (
<VirtualizedList
ref={(refs) => (flatListRef.current = refs)}
data={DATA}
initialNumToRender={20}
renderItem={renderItem}
keyExtractor={keyExtractor}
getItemCount={() => data.length}
getItem={(_, index) => getItem(_, index, focusedRank)}
contentContainerStyle={{padding: 10}}
onScrollToIndexFailed={(info) => {
const wait = new Promise((resolve) => setTimeout(resolve, 500));
wait.then(async () => {
flatListRef.current.scrollToOffset({
offset: info.averageItemLength * info.index,
animated: true,
});
await flatListRef.current?.scrollToIndex({
index: focusedRank,
animated: true,
});
});
}}
/>
)
If I could change index or shift by focusedRank the problem's solved.
Why don't you use Flatlist. And also Flatlist has onLayout you could implement it using regression algorithm or like that. By implementing it you have a simple time to navigate between paragraph anymore

How to use scrollToLocation in sectionList to scroll to specific location

I have a SectionList as follows,
<SectionList
ref={ref => this.sectionListRef = ref}
renderItem={({ item, index, section }) => this.renderItems(item, index, section)}
renderSectionHeader={({section: {title}}) => this.renderSectionHeader(title)}
stickySectionHeadersEnabled={false}
sections={openRequestsArrLength > 0 ? openRequestsArr : []}
onScroll={(e) => this.handleScroll(e)}
/>
and below is the code to take the user to desired list item
this.sectionListRef.scrollToLocation({
viewOffset: scrollPosition,
animated: false,
itemIndex,
sectionIndex
});
when this code executes getting following error,
scrollToIndex should be used in conjunction with getItemLayout or
onScrollToIndexFailed
I am not sure about how to user neither getItemLayout nor onScrollToIndexFailed.
Can anybody let me know how can i proceed form this point to achieve my requirement that scrolling to desired location?
Thank You.
Edit: getItemLayout didn't solve my problem, it just prevent the error that stated above. Any suggestions on how to use onScrollToIndexFailed to make scrollToLocation works

How to solve blink image in react-native-snap-carousel?

How to solve blink image when back to first item in react-native-snap-carousel ? I try to look for many examples but fail all.
This is my script :
renderSlider ({item, index}) {
return (
<View style={styles.slide}>
<Image source={{uri: item.cover}} style={styles.imageSlider} />
</View>
);
}
<Carousel
ref={(c) => { this._slider1Ref = c; }}
data={data}
renderItem={this.renderSlider}
sliderWidth={width}
itemWidth={(width - 30)}
itemWidth={(width - 30)}
inactiveSlideScale={0.96}
inactiveSlideOpacity={1}
firstItem={0}
enableMomentum={false}
lockScrollWhileSnapping={false}
loop={true}
loopClonesPerSide={100}
autoplay={true}
activeSlideOffset={50}
/>
the comple documentation you can find here and about the plugin api you can find here.
Please anyone help me.
Thanks.
I had the same issue when loop={true} was set.
We came up with this workaround:
We maintained the activeSlide value in a state, and created a reference of Carousel refCarousel.
const [activeSlide, setActiveSlide] = useState(0);
const refCarousel = useRef();
Then we added code in useEffect to manually move the carousel item to the first one back when it reaches the end with a delay of 3500 milliseconds which is also set to autoplayInterval props.
This way, we achieved the looping effect.
useEffect(() => {
if (activeSlide === data.length - 1) {
setTimeout(() => {
refCarousel.current.snapToItem(0);
}, 3500)
}
}, [activeSlide]);
Below is the Carousel component declaration. Only the relevant props are shown here.
<Carousel
ref={refCarousel}
...
//loop={true}
autoplay={true}
autoplayDelay={500}
autoplayInterval={3500}
onSnapToItem={(index) => setActiveSlide(index)}
/>
use React Native Fast Image if you are facing blinking issue.

How to Highlight Updated Items onRefresh of FlatList

I set up a FlatList with an onRefresh function to update the state when the user drags down the screen. It works properly, however I was wondering how I can highlight items in the FlatList that have been updated after the refresh.
Say, for example, I want to change the background for a few seconds for any item in the list that was updated, then return to normal.
<FlatList
data={scores}
renderItem={({item}) => (
<View style={styles.scoreContainer}>
<ScoreRow data={item.away} />
<ScoreRow data={item.home} />
</View>
)}
keyExtractor={item => item.gameID}
refreshing={isRefreshing}
onRefresh={updateScores}
/>
The best I could do was add a useEffect in the ScoreRow component to detect if something changes within that component, but that only allows me to update one component at a time, not the entire View.
const [runUpdate, setRunUpdate] = useState(false)
const [runs, setRuns] = useState(data.R)
useEffect(() => {
if(runs !== data.R) {
setRunUpdate(true)
setRuns(data.R)
setTimeout(() => setRunUpdate(false), 10000)
}
}, [data.R])
I can't figure out how to detect a change on an an item in the View of the FlatList so that I can change the entire View the way I did each component.
You can achieve this by using data of FlatList. You have to make an extra parameter for this.
eg:
//Method to refresh data
_refreshMethod() {
// Do your code to fetch...
...
let newDataArray = data // Data fetch from server or some thing.
let updatedArray = []
newDataArray.map((data, index) => {
data["isNewItem"] = true;
updatedArray.push(data);
});
this.setState({scores: updatedArray})
this._callTimer()
}
// Method to update new item status after a delay
_callTimer() {
setTimeout(function() {
let updatedArray = []
this.state.scores.map((data, index) => {
data["isNewItem"] = false;
updatedArray.push(data);
});
this.setState({scores: updatedArray})
}, 3000); // The time you want to do...
}
Then change the style of row based on the state value.
<FlatList
data={this.state.scores}
renderItem={({item}) => (
<View style={item.isNewItem ? styles.yourNewItemStyle : styles.scoreContainer}>
<ScoreRow data={item.away} />
<ScoreRow data={item.home} />
</View>
)}
keyExtractor={item => item.gameID}
refreshing={isRefreshing}
onRefresh={updateScores}
extraData={this.state}
/>