We will be going through the React Hooks concept and their use cases upon FlatList implementation in React Native. Let’s catch the idea of creating a FlatList from scratch and build the on-demand data fetch logic along with this article. Also, we can try out the Animated API upon scrolling event too!

How to use FlatList with Hooks in React Native?

The FlatList in Hooks. And probably, some performance optimization configurations.

Sean Pang
Sean Pang
Apr 29 · 6 min read
Image for post
Image for post
Image credit: Tatiana Rodriguez

React Hooks?

Therefore, Hooks will be used in React function components only instead of React Component Classes.

Bear in mind that the rules we need to follow, the do and don’t, as outlined in the Hooks Documentation.

  • Do not call Hooks inside loops or nested functions, let alone in a conditional logic.
  • Do Call Hooks at the very top point where your React function starts.

“WHY?”

Imagine the working theory of a sequence, or maybe you can think of how an array works to understand it better.

In the case of render process in React, Hooks will be called in the exact same order for every render. If you get mess up with the order that calls within render, it might lead to data inconsistency. And this scenario is prohibited.

We will probably pass the topic of “unpacking how Hooks work” in this article, if you are interested for sure you might find some relevant articles elsewhere.

First of all… Hooks use cases!

1. Use them in functional components instead of classes…

2. Call them at the very top where the function starts…

...
const ItemList = props => {
const [limit, setLimit] = useState(5);
const [page, setPage] = useState(1);
const [clientData, setClientData] = useState([]);
const [serverData, serverDataLoaded] = useState([]);
const [pending_process, setPending_process] = useState(true);
const [loadmore, setLoadmore] = useState(false);
...
}

Let’s have a dummy database set as below :

const itemList = [
{id: '1', name: 'Item!'},
{id: '2', name: 'Item@'},
{id: '3', name: 'Item#'},
{id: '4', name: 'Item$'},
{id: '5', name: 'Item%'},
{id: '6', name: 'Item^'},
{id: '7', name: 'Item&'},
{id: '8', name: 'Item*'},
{id: '9', name: 'Item('},
{id: '10', name: 'Item)'},
{id: '11', name: 'Item!!'},
{id: '12', name: 'Item@@'},
{id: '13', name: 'Item##'},
{id: '14', name: 'Item$$'},
{id: '15', name: 'Item%%'},
{id: '16', name: 'Item^^'},
{id: '17', name: 'Item&&'},
{id: '18', name: 'Item**'},
{id: '19', name: 'Item(('},
{id: '20', name: 'Item))'}
];

We add some simulation functions for API calls as below:

// delay for 1500ms to simulate a API request time.
// we start with page = 1.
// itemList is a constants dataset as show above.
const ApiRequest = async thePage => {
await setTimeout(() => {}, 1500);
return itemList.slice((thePage - 1) * limit, thePage * limit);
};
const requestToServer = async thePage => {
let data = await ApiRequest(thePage);
serverDataLoaded(data);
};

We then set the API response data into our state variable — “serverData”.

Next, we proceed to “useEffect” Hook.

“useEffect” Hook serves the same purposes of some lifecycle processes, namely componentDidMount, componentDidUpdate and componentWillUnmount, and it performs their side effects in the particular functional component.

Let’s make our first call to our D-I-Y “API” to fetch data with “useEffect” Hook. We only want the Hook to run once to get the very first set of data upon initial render. Hence, we pass in an empty array to the second argument.

useEffect(() => {
requestToServer(page); // page => 1
}, []);

We add this to manage the side effects of serverData state.
See, the second argument now is fed with [serverData] and we expect some side effects upon serverData state change: we will merge them with clientData for display.

useEffect(() => {
setClientData([...clientData, ...serverData]);
}, [serverData]);

Again we build another Hook to observe the page state. Upon page change, we request data from “the server”, again.

useEffect(() => {
requestToServer(page);
}, [page]);

And a “handleLoadMore” function is basically used to handle page change.

const handleLoadMore = () => {
setPage(page + 1);
};

Secondly… FlatList Usecase!

<FlatList
data={clientData}
renderItem={renderRow}
onEndReached={handleLoadMore}
onEndReachedThreshold={0.1}
onRefresh={() => onRefresh()}
/>

After adding in the logic, we have something similar to below:

Few additional things to focus here:

  • onEndReachedThreshold | number
  • onEndReached | function
  • onRefresh | function
  • pending_process | state
  • loadmore | state

The onEndReachedThreshold

Is the measure unit of distance from the bottom edge of the list before onEndReached callback is triggered. It’s ranged from 0 - 1. For a value of 0.1, it means when the content is scrolled to 90% of its visible length, the onEndReached will fire!

The onRefresh

Is a callback for refresh. What does it mean by refresh here? It’s a “pull to refresh” behavior!

The pending_process

Is a state we use to control the request time of the API call, one after another, for the sake of data management and prevent API spams!

While the loadmore

Is another state we keep track to grant permission for subsequent API call(s) when there are records coming!

Output:

Image for post
Image for post
Simple FlatList with Mock API Request

Thirdly… Animated API!

See the skeleton for an Animated.FlatList below:

import { Animated } from 'react-native';const ItemList = props => {
...
const [scrollY, setScrollY] = useState(new Animated.Value(0));
const [op, setOp] = useState(
scrollY.interpolate({
inputRange: [0, 50, 100, 150],
outputRange: [1, 0.5, 0.25, 0]
}));
...
const renderRow = ({item, index, separators}) => {
return (
<Animated.View style={{opacity: op}}>
<ListItem
style={{
height: ITEM_HEIGHT,
backgroundColor: Constants.COLOR.GOLD
}}>
<Text style={{color: 'white'}}>{item.name}</Text
</ListItem>
</Animated.View>
)
}
...
return (
<Animated.FlatList
...
onScroll={Animated.event(
[
{
nativeEvent: {contentOffset: {y: scrollY}},
},
],
{
useNativeDriver: true,
listener: handleScroll
},
)}
/>
);
}

scrollY : new Animated.Value(0)

is defined to serve as an Animated instance, with a starting value of 0.

Op : scrollY.interpolate({ inputRange, outputRange })

is the changing style of in terms of opacity[outputRange] as relative to the scroll Y-axis[inputRange] we expected.

Image for post
Image for post
Scroll To Top Opacity Change

Yes it is! And finally… We are heading to some optimization configurations for the FlatList!

Extra Tuning?

1. Use getItemLayout

This method is highly desirable as this will certainly cut out the needs for FlatList to run some asynchronous layout calculation processes if we have defined the height for each list item.

2. Apply keyExtractor props to FlatList

This props is used by the FlatList to do caching and tracking primarily with key supplied.

3. Avoid feeding anonymous function to “renderItem” props

We used to move the “renderItem” function out to prevent recreation upon each render process.

4. Use useMemo Hooks to replace “shouldComponentUpdate”

We use useMemo Hooks to observe props change before render. As what had been done by “shouldComponentUpdate” upon React’s PureComponent.

Summary :

import React, {useState, useEffect, useMemo} from 'react';
import { Dimensions } from 'react-native';
...
...
const {height} = Dimensions.get('window');
const ITEM_HEIGHT = height * 0.25;
const ItemListDemo = props => {
...
...
const keyExtractor = (item, index) => item.id;
const getItemLayout = (data, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index
});
return useMemo(() => {
return (
<FlatList
...
keyExtractor={keyExtractor}
data={clientData}
renderItem={renderRow}
getItemLayout={getItemLayout}
/>
);
}, [clientData, fadingIndex]);
};
}

Conclusion:

We have learned the basics for React Hooks from the very first section of the article and also we have come across some hands-on programming experience using useState and useEffect Hooks in the subsequent parts.

Secondly we have run through the FlatList from scratch with on-demand data fetch logic, followed by Animated API to control opacity styling of the list item.

Finally we have also gone through some performance configurations for the FlatList in React Native!

It helps? Happy coding.

If this guided you well. You may leave some appreciation !

The Startup

Medium's largest active publication, followed by +732K people. Follow to join our community.

Sean Pang

Written by

Sean Pang

Engineer. #reactjs #react-native #vuejs #nodejs #PHP #AWS

The Startup

Medium's largest active publication, followed by +732K people. Follow to join our community.

Sean Pang

Written by

Sean Pang

Engineer. #reactjs #react-native #vuejs #nodejs #PHP #AWS

The Startup

Medium's largest active publication, followed by +732K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium