How to use scrollToLocation in sectionList to scroll to specific location - react-native

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

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 make a flat list scroll Infinitely in React Native With a Finite Amount of data in Array

I have flat list horizontally set
with data of 11 items coming from an array, which is fixed and never changes
what I want is when user reaches at the end of flat list while scrolling, the data should remain the same but the first item should
show up in the last and then so on
here is what I have tried so far
<FlatList
{...this.props}
ref={ref => {
this.infListRef = ref;
}}
data={this.props.data}
onScrollEndDrag={this.handleScroll}
initialScrollIndex={0}
scrollEventThrottle={16}
renderItem={this.props.renderItem}
onScroll={({nativeEvent}) => this.checkScroll(nativeEvent)}
horizontal
showsHorizontalScrollIndicator={false}
keyExtractor={item => item.id}
/>
Any help will be highly appreciated.
Basically, implementing onScroll usage is when you want to be noticed when the actually scroll related to the scroll position (aminations for instance). When you would like to be notified when the user reaches, or about to reach, to the end of the FlatList.
You should implement onEndReached and onEndReachedThreshold to handle a better user experience when the user reaches the threshold.
The new data you're getting from the source (server or no matter wherefrom) should be concatenated to existing this.props.data
See good blog post - https://scotch.io/tutorials/implementing-an-infinite-scroll-list-in-react-native
And this SO answers - React Native Infinite Scroll
My solution refers to pagination because infinite scroll is a private case of pagination, it's the exact same approach.
If you want image or video list
One other approach which is kind a hack and an easy one is using react-native-snap-carousel
<Carousel
ref={ (c) => { this._carousel = c; } }
data={this.state.data}
renderItem={this._renderItem.bind(this)}
onSnapToItem={this.handleSnapToItem.bind(this)}
sliderWidth={360}
itemWidth={256}
layout={'default'}
firstItem={0}
itemHeight={20}
sliderHeight={20}
loop
vertical
loopClonesPerSide={100}
/>
Example:
https://snack.expo.io/#kurtesy/react-native-snap-carousel-example
You can achieve this using onEndReached method of Flatlist.
This is the idea behind answer.
state = {
data: [] //your initial data
}
<Flatlist
{…this.props}
extraData={this.state}
onEndReached = {() => {
this.setState((prevState) =>{
data: […prevState,this.state.data]
)}}
/>

Using a paged FlatList, how to get an event on visible page changed?

I am building a simple horizontal React Native FlatList with paging enabled:
<FlatList
horizontal={true}
pagingEnabled={true}
data={...some data...}
renderItem={({item}) => {...some rendering...}}
onViewableItemsChanged={(info) => {... handling ...}}
/>
I would like to get called back only after a new page in the list has been made visible. The behavior that I am seeking is that, as the user swipes the list left and right, the list will page through the items and I want the callback to fire once with the visible items.
The onViewableItemsChanged props is called on every change in visible items which is not what I am looking for, unless I keep track on which page the items belong to.
I am looking for a onViewablePageChanged type of callback.
Any ideas on how to achieve this?
The solution I used was to track the viewable items against the overall list of items to determine the "page" number of viewable items.
By using pagingEnabled, the list will only show pages.
However onViewableItemsChanged is called back on every changes to the viewable items. By comparing the viewable items againts the list of items, one can figure out on which "page" the FlatList is.
This requires that one knows how many items can be displayed in the view. Either calculated based on layout or set in the View and FlatList rendering.
Here's an example:
onViewableItemsChanged = ({viewableItems}) => {
// Get the first viewable item
const firstViewableItem = viewableItems[0].key;
// Get its index into the items
const index = this.state.items.findIndex(item => item.key === firstViewableItem);
// If the index is a multiple of the number of items displayable on the screen
// by checking for a reminder on the modulo operation
if ((index % NB_ITEMS_SCREEN) === 0) {
// get page
const currentPage = index / NB_ITEMS_SCREEN;
if (currentPage !== this.state.currentPage) {
// Do something and update currentPage in this.state
}
}
}
<FlatList
data={this.state.items}
horizontal={true}
pagingEnabled={true}
renderItem={({ item }) => <Text>{item.key}</Text>}
onViewableItemsChanged={this.onViewableItemsChanged}
/>
See this snack
https://snack.expo.io/#visto9259/flatlist-onviewableitemschanged-example
You can achieve visible items by using below code. Try this.
//Method to invoke when item change
onViewableItemsChanged = ({ viewableItems, changed }) => {
console.log("Visible items are", viewableItems);
console.log("Changed in this iteration", changed);
}
render () => {
return (
...
<FlatList
horizontal={true}
pagingEnabled={true}
data={...some data...}
renderItem={({item}) => {...some rendering...}}
onViewableItemsChanged={this.onViewableItemsChanged }
viewabilityConfig={{
itemVisiblePercentThreshold: 50
}}
/>
....
)}

Prevent Flatlist from scrolling when new items are added

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