I have a Flatlist that displays cards and information in it, I have to apply pagination to it i.e at first only 3 cards should load on reaching end more 3 cards should load.
Below is my code :
<FlatList
style={{ height: HEIGHT, flex: 1 }} // declared a HEIGHT const with value of windows height
data={this.state.show_data_list} // data to be shown in flatlist
keyExtractor={(x, i) => x + i}
extraData={this.state.refresh} // to sort the data based on condition.
initialNumToRender={3} // data to be loaded initially
onEndReached={() => this.loadMoreData()} // function which add 3 more items to show_data_list state to be shown in flatlist
onEndReachedThreshold={10}
renderItem={({ item }) =>
<ContentCard
// content to display
/>
}
/>
As soon as the view renders all data is shown, in other words, onEndReached is called before I reach at the end.
Can any of u guys know why this is happening ????
Implement onMomentumScrollBegin or check the distance from the end
onEndReached={({ distanceFromEnd }) => {
if (distanceFromEnd < 0) return;
}
Please refer link
Related
Hey I have a FlatList with Cards Items. And I want to achieve this scenario.
Scenario:
When Scrolling for example through 5 items in the Flatlist I want to show a feedback card instead of an item Card
How Can this by Implemented ?
In the renderItem method, you can access the index of the current card.
My suggestion would be rendering the feedback card right after every 5th item card.
A rough example will look like this (Not tested yet)
const SampleApp = () => {
const renderItem = ({ item, index }) => {
return (
<>
<ItemCard item={item} />
{(index > 0 && index % 5 === 0) ? <FeedbackCard /> : null}
</>
);
};
return <FlatList data={DATA} renderItem={renderItem} />;
};
You can try following - track onScroll event for FlatList, check if you passed enough offset for 5 Rows, compute target row position and insert feedback card there in FlatList data.
I have a FlatList that fetches a list of jobs from the API. When the end of the list is reached on scrolling, the next set of jobs is fetched from the API and appended to the job list.
The following is the code for FlatList
<View style={localStyles.container}>
<FlatList
data={jobList.jobs}
renderItem={renderJobList}
keyExtractor={item => "" + item.jid}
onEndReachedThreshold={0.2}
onRefresh={() => { getJobsList(true) }}
refreshing={fetchingStatus}
extraData={jobList.jobs, fetchingStatus, savedIds, stateChanged}
ListFooterComponent={<ProgressIndicator inProgress={fetchingStatus} />}
onEndReached={() => {
getJobsList(false);
}} />
</View>
jobList, fetchingStatus, savedIds, stateChanged - these 4 are state variables
In the JobsListClass, the following is the code for appending the data -
request.processRequest().then((value) => {
this.jobs = this.jobs.concat(value.jarr)
...
this.notify();
}).catch((error) => {
console.log("campus err", error)
...
this.notify();
});
Have tried Array.prototype.push.apply(this.jobs, value.jarr); instead of jobs.concat in the above code but did not help.
I can‘t see what exactly cause the jumping, I would need more code to determine where this happen.
Take a look at the infinite scrolling expo snack
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]
)}}
/>
I need to show the index and bottom of the list while click on the up and down button.
Is any option to show only 15 items up or down If I click on the up or down arrow.
For Eg) Consider a list has 500 items. It has an up and down arrow. If I click on the down arrow once I need to show only 15 items for the first time and If click on the down arrow next need to show the next 15 items.
Also If I click on the up arrow it needs to show 15 items above not all
In this usecase I need to move up and down of the screen. Any option to modify the scrollToIndex and scrollToEnd in Flatlist to achieve this use case
upButtonHandler = () => {
//OnCLick of Up button we scrolled the list to top
this.ListView_Ref.scrollToOffset({ offset: 0, animated: true });
};
downButtonHandler = () => {
//OnCLick of down button we scrolled the list to bottom
this.ListView_Ref.scrollToEnd({ animated: true });
};
<TouchableOpacity
activeOpacity={0.5}
onPress={this.downButtonHandler}
style={styles.downButton}>
<Image
source={{uri:'https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_down.png',
}}
style={styles.downButtonImage}
/>
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.5}
onPress={this.upButtonHandler}
style={styles.upButton}>
<Image
source={{uri:'https://raw.githubusercontent.com/AboutReact/sampleresource/master/arrow_up.png',
}}
style={styles.upButtonImage}
/>
</TouchableOpacity>
You can slice the data provided to the FlatList every time a button is pressed.As the FlatList is a pure Component you need to pass a extra prop to re render the FlatList after button is pressed
Maintain a state variable such as section which describes which part of data to display like (0,15),(15,30),...
Update this variable inside the up and down buttons,taking care of the boundaries so as not to get bad results.This is easily solved by wrapping setState inside a if condition so it will look roughly as
updateSectionLow = () => {
const { section } = this.state;
if (section > 0) {
this.setState({
section: section - 1,
});
}
};
updateSectionHigh = () => {
const { section, data } = this.state;
if (data.length > (section + 1) * 15) {
this.setState({
section: section + 1,
});
}
};
and the FlatList looks like this
<FlatList
data={this.state.data.slice(this.state.section*15,(this.state.section+1)*15)}
renderItem={({ item }) => {
return (
<View style={styles.row}>
<Text>{item.data}</Text>
</View>
);
}}
extraData={this.state.section}
/>
Here is a working expo demo
EDIT
After having discussion with the OP person,i have changed my code little bit.
Get the offset after scroll,
for a vertical list
onMomentumScrollEnd={e => this.scroll(e.nativeEvent.contentOffset)}
Inside the handler
this.setState({
index: Math.floor(offset.y / (ITEM_HEIGHT+SEPARATOR_HEIGHT)),
});
if there is no separator then you can put SEPARATOR_HEIGHT to be 0
and it is only matter of using scrollToOffset with ref as follows
for going down the list by ITEMS_DISP(like 15)
this.flatListRef.scrollToOffset({
offset:(this.state.index+ITEMS_DISP)*ITEM_HEIGHT+(this.state.index+ITEMS_DISP)*SEPARATOR_HEIGHT
});
for going top the list by some ITEMS_DISP
this.flatListRef.scrollToOffset({
offset:(this.state.index-ITEMS_DISP)*ITEM_HEIGHT+(this.state.index-ITEMS_DISP)*SEPARATOR_HEIGHT
});
Updated demo link
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
}}
/>
....
)}