React Native FlatList Optimization (2025): Smooth Scrolling with Expo & TypeScript
Note: This guide uses React Native 0.75.4 and Expo SDK 51, which remain supported as of August 2025 for React Native 0.75 compatibility. Expo SDK 53 offers improved features, including enhanced New Architecture support. For new projects, consider using SDK 53 and enabling the New Architecture early to avoid deprecations of the old architecture expected by late 2025 or early 2026. Check reactnative.dev and docs.expo.dev for updates if using newer versions like React Native 0.76 or Expo SDK 53.
Tooling Compatibility Matrix
Tool | Version | Notes |
---|---|---|
React Native | 0.75.4 | Compatible with Expo SDK 51 |
Expo | ~51.0.0 | Supports EAS Build/Update, New Architecture |
Node.js | 20.x (LTS) | Required for EAS CLI |
Xcode | 16+ | iOS 18 SDK, macOS only |
Android Studio | 2024.3.2+ | Android SDK 35, NDK r25+ |
Axios | 1.11.0 | For data fetching in examples |
Optimizing FlatList
in React Native ensures smooth scrolling for large datasets, enhancing user experience on iOS (Xcode 16+, iOS 18 SDK) and Android (SDK 35). This guide shows you how to optimize FlatList
in React Native 0.75.4 with Expo SDK 51, leveraging FlatList configuration, render optimization, and data fetching with Axios. Expo SDK 51 supports the New Architecture, including bridgeless mode, for improved performance. We’ll use TypeScript for type safety and Over-The-Air (OTA) updates via EAS for deployment. For upgrading to newer React Native versions, see the React Native upgrade guide. For pre-optimized templates, explore Instamobile or Dopebase.
Let’s create a smooth-scrolling FlatList
!
Prerequisites
Ensure you have:
- Node.js (v20.x or later, LTS): nodejs.org
- npm (v10.x or later)
- EAS CLI: For Expo management
- Android Studio (2024.3.2+): Android SDK 35, NDK r25+
- Xcode (16+): iOS 18 SDK (macOS only)
- VS Code or similar editor
- Git: For version control
- A React Native project (Expo SDK 51)
- A REST API endpoint (e.g., jsonplaceholder.typicode.com)
- macOS: For iOS builds
Note: Expo Go supports SDK 51 but may have limitations with custom native code or New Architecture features. Use Expo Snack for quick prototyping.
What is FlatList? FlatList
is a React Native component that efficiently renders large lists using virtualization, displaying only visible items to save memory and boost performance. Learn more in React Native’s FlatList guide.
Step 1: Set Up Your Project
Create a React Native project with TypeScript and configure it for FlatList
optimization.
1.1 Create Project
Install EAS CLI:
npm install -g eas-cli
Create a project:
npx create-expo-app MyApp --template blank-typescript
Navigate to the project:
cd MyApp
1.2 Configure app.config.js
Update app.config.js
for OTA updates and flexibility:
export default () => ({
name: "MyApp",
slug: "myapp",
version: "1.0.0",
orientation: "portrait",
icon: ".https://docs.instamobile.io/assets/icon.png",
splash: {
image: ".https://docs.instamobile.io/assets/splash.png",
resizeMode: "contain",
backgroundColor: "#ffffff"
},
ios: {
bundleIdentifier: "com.myapp.app",
buildNumber: "1.0.0"
},
android: {
package: "com.myapp.app",
versionCode: 1
},
updates: {
enabled: true,
url: "https://u.expo.dev/your-project-id",
checkAutomatically: "ON_LOAD",
fallbackToCacheTimeout: 0
}
});
1.3 Test Locally
Run the app:
npx expo start
Press i
for iOS or a
for Android to verify setup. Use Expo Snack for quick testing without local setup.
Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount 🔥
Get the Mega BundleStep 2: Configure FlatList Props
Optimize FlatList configuration for smooth scrolling.
2.1 Install Dependencies
Add Axios for data fetching:
npm install [email protected]
2.2 Set Up Basic FlatList
Update src/App.tsx
with an optimized FlatList
:
import { useEffect, useState } from 'react';
import { View, Text, FlatList } from 'react-native';
import axios from 'axios';
type Item = { id: number; title: string };
export default function App() {
const [items, setItems] = useState<Item[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchItems = async () => {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
setItems(response.data);
} catch (error) {
console.error('Error fetching items:', error);
} finally {
setLoading(false);
}
};
fetchItems();
}, []);
return (
<View style={{ flex: 1, padding: 20 }}>
{loading ? (
<Text>Loading...</Text>
) : (
<FlatList
data={items}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => <Text>{item.title}</Text>}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
/>
)}
</View>
);
}
What is FlatList configuration? Optimizing props like initialNumToRender
, maxToRenderPerBatch
, and removeClippedSubviews
reduces rendering overhead, ensuring smoother scrolling.
Step 3: Optimize Render Items
Improve render optimization for FlatList
items.
3.1 Create Reusable Item Component
Create src/components/Item.tsx
for optimized rendering:
import { memo } from 'react';
import { View, Text, StyleSheet } from 'react-native';
type Props = { title: string };
const Item = ({ title }: Props) => (
<View style={styles.container}>
<Text>{title}</Text>
</View>
);
const styles = StyleSheet.create({
container: { padding: 10, borderBottomWidth: 1, borderBottomColor: '#ccc' },
});
export default memo(Item);
3.2 Update FlatList
Update src/App.tsx
to use the memoized component:
import { useEffect, useState } from 'react';
import { View, Text, FlatList } from 'react-native';
import axios from 'axios';
import Item from './components/Item';
type ItemType = { id: number; title: string };
export default function App() {
const [items, setItems] = useState<ItemType[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchItems = async () => {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
setItems(response.data);
} catch (error) {
console.error('Error fetching items:', error);
} finally {
setLoading(false);
}
};
fetchItems();
}, []);
return (
<View style={{ flex: 1, padding: 20 }}>
{loading ? (
<Text>Loading...</Text>
) : (
<FlatList
data={items}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => <Item title={item.title} />}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
/>
)}
</View>
);
}
What is render optimization? Using memo
prevents unnecessary re-renders of list items when props are unchanged, improving performance.
Step 4: Fetch Data Efficiently
Optimize data fetching to reduce load times.
4.1 Create API Service
Create src/api/api.ts
:
import axios, { AxiosInstance } from 'axios';
const api: AxiosInstance = axios.create({
baseURL: 'https://jsonplaceholder.typicode.com',
timeout: 10000,
});
export const getItems = async () => {
try {
const response = await api.get('/posts');
return response.data;
} catch (error) {
throw new Error('Failed to fetch items');
}
};
4.2 Update App with API Service
Update src/App.tsx
:
import { useEffect, useState } from 'react';
import { View, Text, FlatList } from 'react-native';
import { getItems } from './api/api';
import Item from './components/Item';
type ItemType = { id: number; title: string };
export default function App() {
const [items, setItems] = useState<ItemType[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchItems = async () => {
try {
const data = await getItems();
setItems(data);
} catch (error) {
console.error('Error fetching items:', error);
} finally {
setLoading(false);
}
};
fetchItems();
}, []);
return (
<View style={{ flex: 1, padding: 20 }}>
{loading ? (
<Text>Loading...</Text>
) : (
<FlatList
data={items}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => <Item title={item.title} />}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
/>
)}
</View>
);
}
Step 5: Test FlatList Performance
Verify smooth scrolling with automated and manual tests.
5.1 Set Up Automated Tests
Install testing dependencies:
npm install --save-dev jest @types/jest ts-jest @testing-library/react-native @testing-library/jest-native
Configure package.json
:
{
"scripts": {
"test": "jest"
},
"jest": {
"preset": "react-native",
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
"setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"]
}
}
Add test in src/__tests__/App.test.tsx
:
import { render, waitFor } from '@testing-library/react-native';
import App from '../App';
import { getItems } from '../api/api';
import axios from 'axios';
jest.mock('axios');
test('renders FlatList items', async () => {
const mockItems = [{ id: 1, title: 'Test Item' }];
axios.get.mockResolvedValue({ data: mockItems });
const { getByText } = render(<App />);
await waitFor(() => expect(getByText('Test Item')).toBeTruthy());
});
Run tests:
npm test
5.2 Manual Testing
Test scrolling on iOS/Android devices with large lists to ensure smoothness.
Step 6: Deploy with OTA Updates
Deploy optimizations with Over-The-Air (OTA) updates via EAS.
6.1 Configure OTA
Install expo-updates
:
npm install expo-updates
Check compatibility at docs.expo.dev.
Ensure app.config.js
includes OTA settings (Step 1.2).
Update src/App.tsx
for OTA updates:
import { useEffect, useState } from 'react';
import { View, Text, FlatList } from 'react-native';
import * as Updates from 'expo-updates';
import { getItems } from './api/api';
import Item from './components/Item';
type ItemType = { id: number; title: string };
export default function App() {
const [items, setItems] = useState<ItemType[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const checkForUpdates = async () => {
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
await Updates.fetchUpdateAsync();
await Updates.reloadAsync();
}
} catch (e) {
console.error('Update check failed:', e);
}
};
if (!__DEV__) {
checkForUpdates();
}
const fetchItems = async () => {
try {
const data = await getItems();
setItems(data);
} catch (error) {
console.error('Error fetching items:', error);
} finally {
setLoading(false);
}
};
fetchItems();
}, []);
return (
<View style={{ flex: 1, padding: 20 }}>
{loading ? (
<Text>Loading...</Text>
) : (
<FlatList
data={items}
keyExtractor={item => item.id.toString()}
renderItem={({ item }) => <Item title={item.title} />}
initialNumToRender={10}
maxToRenderPerBatch={10}
windowSize={5}
removeClippedSubviews={true}
/>
)}
</View>
);
}
6.2 Publish Update
Configure EAS Update:
eas update:configure
Publish:
eas update --branch production
Test with a preview build:
eas build --profile preview --platform all
Troubleshooting Tips
- Slow Scrolling: Adjust
initialNumToRender
andwindowSize
in FlatList configuration. Ensurememo
is used in render optimization. - Data Fetching Issues: Verify API endpoint and network. Log errors with
console.error
. - Android Build Hangs: For React Native 0.75.4, check Gradle memory settings or clear caches (
./gradlew clean
). See Stack Overflow for solutions. - Dependency Issues: Run
npm list
and update per Expo’s compatibility guide. - Build Fails: Ensure Xcode 16+ and Android SDK 35. Clear caches (
rm -rf ~/Library/Developer/Xcode/DerivedData
or./gradlew clean
). - OTA Issues: Verify
EXPO_TOKEN
andapp.config.js
’supdates.url
. Runeas update:configure
.
End-of-Article Recap
You’ve learned to:
- Optimize FlatList configuration with props like
initialNumToRender
andremoveClippedSubviews
. - Improve render optimization with
memo
for efficient rendering. - Perform data fetching with Axios and deploy updates via OTA, leveraging Expo SDK 51’s New Architecture support.
Quick Reference Checklist
- Create project with
npx create-expo-app MyApp --template blank-typescript
. - Configure
app.config.js
with OTA settings. - Install Axios (
npm install [email protected]
) for data fetching. - Set up FlatList configuration with optimized props.
- Create memoized item component for render optimization.
- Implement API service in
src/api/api.ts
. - Test with Jest and manual scrolling on devices.
- Deploy updates with EAS Update (
eas update --branch production
).
Looking for a custom mobile application?
Our team of expert mobile developers can help you build a custom mobile app that meets your specific needs.
Get in TouchConclusion
You’ve optimized FlatList
in your React Native 0.75.4 app with Expo SDK 51, ensuring smooth scrolling with Axios 1.11.0 and OTA updates via EAS. For new projects, adopt Expo SDK 53 with the New Architecture to future-proof against old architecture deprecations. For upgrading to newer React Native versions, see the React Native upgrade guide. For pre-optimized templates, explore Instamobile or Dopebase. Dive deeper with Expo’s documentation or join the community at reactnative.dev.
Additional Resources
- dopebase.com - Mobile app development resources and templates
- instamobile.io - Production-ready React Native templates
- instaflutter.com - Flutter templates for cross-platform development
- reactnative.dev - Official React Native documentation
- docs.expo.dev - Expo SDK and EAS documentation
- axios-http.com - Axios documentation
- Expo Snack - Quick prototyping tool