Optimize your React Native app performance
- remove all
console
statements
babel-plugin-transform-remove-console
env: {
production: {
plugins: ['transform-remove-console']
},
}
- Memoize expensive computations with React Hooks
memo
,useMemo
,useCallback
2.1. useMemo
const streetTypes = useMemo(() => {
let topStreetTypes = dataJson.topStreetTypes.map(value => ({ display: value, value }));
let streetType = dataJson.streetTypes.map(value => ({ display: value, value }));
let separator = { display: '--------------', value: '', disable: true };
return [...topStreetTypes, separator, ...streetType];
}, []);
2.2. useCallback
const launchSelectImagesPicker = useCallback(async ({ multiple, option, onConfirm }) => {
const grant = await PermissionLib.requestStoragePermission(true);
if (!grant) {
return [];
}
const configs = multiple ? DEFAULT_OPTIONS.multiple : merge(option, DEFAULT_OPTIONS.image);
openPicker(configs)
.then(images => {
const result = multiple ? images : [images];
isFunction(onConfirm) && onConfirm(transformImages(result));
})
.catch(error => {
if (error.message) {
GlobalLib.Toast.get().toastWarning(error.message);
}
});
}, []);
2.3. memo
function MyComponent(props) {
/* render using props */
}
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
export default React.memo(MyComponent, areEqual);
-
Use
FlatList
orSectionList
to render large lists instead ofScrollView
-
Resize image and cache locally resize
- using PNG format
- using smaller-resolution images cache
- use
react-native-fast-image
prefetch/preload image =>
-
Animations: 5.1.
InteractionManager
InteractionManager.runAfterInteractions(() => {
...
});
5.2. LayoutAnimation
if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
5.3. Use native driver
Animated.timing(opacity, {
toValue: 1,
duration: 500,
useNativeDriver: true,
}).start();
5.4 Try to use reanimated 2
- Use Hermes
- Reducing memory usage
- Decreasing app size
- Improving the app start-up time
- Avoid Arrow Functions
function TodoComponent () {
...
function addTodo() {
...
}
return (
<Pressable onPress={() => addTodo()} />
);
}
function TodoComponent () {
...
const addTodo = useCallback((data) => {
...
},[]);
return (
<Pressable onPress={addTodo} />
);
}
- TextInput
- The ultimate guide to React native optimization from Callback 8.1. Uncontrolled Inputs
function UncontrolledInputs() {
const [text, onTextChange] = React.useState('Controlled inputs');
return (
<TextInput
style={styles.input}
onChangeText={onTextChange}
defaultValue={text}
/>
);
}
const styles = StyleSheet.create({
input : { borderWidth: 1, height: 100, borderColor: 'blue' }
})
-
Large List Flatlist Props:
removeClippedSubviews
maxToRenderPerBatch
updateCellsBatchingPeriod
initialNumToRender
windowSize
keyExtractor
List items- use basic component,
shouldComponentUpdate
ormemo
- cached optimized images:
react-native-fast-image
getItemLayout
- Avoid anonymous function on renderItem
-
Use Performance Monitoring
- Firebase, Sentry
Android:
- ProGuard https://viblo.asia/p/tim-hieu-ve-proguard-trong-android-924lJ30N5PM#_5-only-obfuscate-your-project-7
- Enable the RAM Format
project.ext.react = [
bundleCommand: "ram-bundle",
]
...
project.ext.react = [
bundleCommand: "ram-bundle",
extraPackagerArgs: ["--indexed-ram-bundle"]
]
- Reduce app size: Link
enableProguardInReleaseBuilds = true
enableSeparateBuildPerCPUArchitecture = true
- Why do we need optimize react native app?
Need:
- make sure 60 FPS and native look and feel to your apps.
- Deliver smooth UI performance by default Structure RN framework: only run one thread.