There are some ways to improve react-native app performance we will discusses one by one
There are many approaches out there to avoid this issue.
1. Use useMemo() and UseCallback() Hooks in functional components
These Hooks reduce re-renderings by caching and returning the same result if the inputs are the same without any computations. When the inputs change, the cache gets invalidated and the new component state gets rendered.
useMemo()
useMemo hook that lets you cache the result of a calculation
between re-renders. let’s consider an example of multiplying 2 numbers.
The above function will compute the result and re-render the component each time it is called, regardless of the inputs. But, if we use the useMemo()
Hook, we can avoid component re-rendering if the inputs are the same and save the result in the cache.const cachedValue = useMemo(() => multiply(x, y), [x, y])
Now, the computed result is stored in the cachedValue
variable and useMemo()
Hook will return it each time unless the inputs are changed
useCallback():
UseCallback()
it does not cache the result. Instead, it memoizes the callback function provided to it.
For example, consider a component with a clickable item list.
[React-Native] import { useCallback } from ‘react’; export function MyParent({ term }) { const onClick = useCallback(event => { console.log(‘Clicked Item : ‘, event.currentTarget); }, [item]); return (In the above example, useCallBack()
memoizes the onClick
callback. So, it will not re-render the component if the user clicks the same item again and again.
2. Replace useState() with useRef()
useState()
Hook is widely used in React applications to re-render the components on state changes. However, there are scenarios where we need to track state changes without re-rendering the components.
But, if we use the useRef()
Hook, we can track the state changes without causing component re-renderings.
The above example has a toggle that re-renders the component each time the value changes. But the counter
persists its value since it is a mutable ref. Since we are using useRef()
, it will only cause a single render. However, if we use useState()
, it will cause 2 renders for each toggle.
This render counter is pretty useful. But what if you could abstract this away into a custom hook, that you could reuse across projects with a simple npm i @bit/your-username/use-render count
? You could do just that using an open-source toolchain like bit
3. Using React Fragments
If you have worked with React before, you will know that React requires wrapping the components with a single parent element. Though it’s not directly about re-rendering, have you known that it affects the overall component rendering time?
As a solution, you can use React Fragments to wrap the components, and it will reduce the load on the DOM, resulting in faster rendering times and decreased memory usage.
[React-Native] const App= () => { return (Hello
World
4. If you are using redux in you react-native for the state management then use batchedSubscribe
The batchedSubscribe
store enhancer accepts a function which is called after every dispatch with a notify
callback as a single argument. Calling the notify
callback will trigger all the subscription handlers, this gives you the ability to use various techniques to delay subscription notifications such as: debouncing, React batched updates or requestAnimationFrame.
Since batchedSubscribe
overloads the dispatch and subscribe handlers on the original redux store it is important that it gets applied before any other store enhancers or middleware that depend on these functions; The compose utility in redux can be used to handle this:
Note: since compose
applies functions from right to left, batchedSubscribe
should appear at the end of the chain.
The store enhancer also exposes a subscribeImmediate
method which allows for unbatched subscribe notifications.
example:
Debounced subscribe handlers
React batched updates:
[React-Native] import { createStore } from ‘redux’; import { batchedSubscribe } from ‘redux-batched-subscribe’; // React <= 0.13 import { addons } from 'react/addons'; const batchedUpdates = addons.batchedUpdates; // React 0.14 import { unstable_batchedUpdates as batchedUpdates } from 'react-dom'; // Note: passing batchedSubscribe as the last argument to createStore requires redux@>=3.1.0 const store = createStore(reducer, intialState, batchedSubscribe(batchedUpdates)); [React-Native]for more info visit : https://www.npmjs.com/package/redux-batched-subscribe
5. API Call Optimization with React Query
It’s common to use the useEffect()
Hook for asynchronous data fetching operations in React applications. However, useEffect()
runs and fetches data on each render, and in most situations, it keeps loading the same data.
As a solution, we can use the React Query library to cache the response data. When we make an API call, React Query will first return the data from the cache before continuing with the request. Then, it will retrieve the data from the server, and if there is no new data available, it will prevent the component from re-rendering.
[React-Native] import React from ‘react’ import {useQuery} from ‘react-query’ import axios from ‘axios’async function fetchArticles(){ const {data} = await axios.get(URL) return data } function Articles(){ const {data, error, isError, isLoading } = useQuery(‘articles’, fetchArticles) if(isLoading){ returnI hope you have found this useful. Thank you for reading!