React Native Lists: Load More by Scrolling

How to progressively load more list items as you scroll in React Native

Loading more items while scrolling

Why Loading More is Important

Pre-populating app list content as a user signs in.

Persisting lists with AsyncStorage

More results are fetched as the user scrolls down.

List Component Setup

Feeding items into FlatList

// structure of list dataexport const data = [
{
_id: 1,
},
{
_id: 2,
},
...
];
// fetchResults takes records from `data` from a particular `_id`const RECORDS_PER_FETCH = 5;export const fetchResults = (startingId = 0) => {
let obj = [];
// loop through records starting at `startingId`
for (
let i = startingId;
i < startingId + RECORDS_PER_FETCH;
i++) {
// break loop if list comes to an end
if (data[i] === undefined)
break;
// add record to `obj`
obj.push(data[i]);
}
return obj;
}

Initialising data from Redux store, then AsyncStorage

Initialising a list from Redux and AsyncStorage, with AsyncStorage the true source of data.
const listItems = useSelector(state => state.list.items);
// call initialisation function with useEffectuseEffect(() => {
initialiseList();
}, []);
const initialiseList = async () => {
...
}
// `initialiseList` function in fullconst initialiseList = async () => {   // [for testing purposes] reset AsyncStorage on every app refresh
await AsyncStorage.removeItem('saved_list');
// get current persisted list items (will be null if above line is not removed)
const curItems = await AsyncStorage.getItem('saved_list');
if (curItems === null) {
// no current items in AsyncStorage - fetch initial items
json = fetchResults(0);
// set initial list in AsyncStorage
await AsyncStorage.setItem('saved_list', JSON.stringify(json));
} else {
// current items exist - format as a JSON object
json = JSON.parse(curItems);
}
// update Redux store (Redux will ignore if `json` is same as current list items)
dispatch({
type: 'UPDATE_LIST_RESULTS',
items: json
});
}

FlatList Component Props

<FlatList
...
data={listItems}
keyExtractor={(item) => "item_" + item._id}
/>
<FlatList
...
onEndReachedThreshold={0.01}
onEndReached={info => {
loadMoreResults(info);
}}
/>

Loading More Results

// `loadMoreResults` function in fullconst loadMoreResults = async info => {   // if already loading more, or all loaded, return
if (loadingMore || allLoaded)
return
// set loading more (also updates footer text)
setLoadingMore(true);
// get next results
const newItems = fetchResults(totalItems);
// mimic server-side API request and delay execution for 1 second
await delay(1000);
if (newItems.length === 0) {

// if no new items were fetched, set all loaded to true to prevent further requests
setAllLoaded(true);

} else {
// process the newly fetched items
await persistResults(newItems);

}
// load more complete, set loading more to false
setLoadingMore(false);
}
// `persistResults` function in fullconst persistResults = async (newItems) => {   // get current persisted list items
const curItems = await AsyncStorage.getItem('saved_list');
// format as a JSON object
let json = curItems === null
? {}
: JSON.parse(curItems);
// add new items to json object
for (let item of newItems) {
json.push(item);
}
// persist updated item list
await AsyncStorage.setItem('saved_list', JSON.stringify(json));
// update Redux store
dispatch({
type: 'UPDATE_LIST_RESULTS',
items: json
});
}

In Summary

Programmer and Author. Director @ JKRBInvestments.com. Creator of LearnChineseGrammar.com for iOS and Android.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store