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.

React Hooks?
Hooks are javascript functions, that allow us to use state without writing up a class.
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!
The rules, remember?
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 :
This is what we will use to replicate the response returned from an API call.
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 can use multiple useEffect Hooks in a function component.
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!
Basic FlatList looks in this way:
<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!
Observe logs below to trace them better … 😉
Output:

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.
We will add in logic. And some calculations for the new Animated Value. And the final content will be similar to …
And the output :

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 !