React Native mobile application is working very slow on every click.
I am using react native v0.40.0
and following are the dependencies of my project.
{
"analytics-react-native": "^1.1.0",
"apisauce": "^0.7.0",
"babel-preset-es2015": "^6.18.0",
"es6-promise": "^4.0.5",
"flow-bin": "^0.36.0",
"geolib": "^2.0.22",
"immutable": "^3.8.1",
"intl": "^1.2.5",
"isomorphic-fetch": "^2.2.1",
"lodash": "^4.17.4",
"lodash.range": "^3.2.0",
"prop-types": "^15.5.10",
"raven-js": "^3.13.1",
"react": "^15.4.2",
"react-native": "^0.40.0",
"react-native-apple-healthkit-rn0.40": "^0.3.2",
"react-native-blur": "^2.0.0",
"react-native-button": "^1.7.1",
"react-native-checkbox": "^2.0.0",
"react-native-code-push": "^1.17.3-beta",
"react-native-datepicker": "^1.4.4",
"react-native-device-info": "^0.10.1",
"react-native-easy-toast": "^1.0.6",
"react-native-fbsdk": "^0.5.0",
"react-native-geocoder": "^0.4.5",
"react-native-gifted-chat": "^0.1.3",
"react-native-global-props": "^1.1.1",
"react-native-image-crop-picker": "^0.15.1",
"react-native-image-picker": "^0.25.1",
"react-native-image-slider": "^1.1.5",
"react-native-keyboard-aware-scroll-view": "^0.2.7",
"react-native-maps": "0.15.2",
"react-native-modal-dropdown": "^0.4.4",
"react-native-popup-menu": "^0.7.2",
"react-native-push-notification": "^2.2.1",
"react-native-radio-buttons": "^0.14.0",
"react-native-router-flux": "3.38.0",
"react-native-segmented-android": "^1.0.4",
"react-native-snap-carousel": "2.1.4",
"react-native-stars": "^1.1.0",
"react-native-swipeout": "^2.2.2",
"react-native-swiper": "^1.5.4",
"react-native-tableview-simple": "0.16.5",
"react-native-vector-icons": "^4.0.0",
"react-native-video": "^1.0.0",
"react-native-zendesk-chat": "^0.2.1",
"react-redux": "^4.4.6",
"recompose": "^0.20.2",
"redux": "^3.5.2",
"redux-thunk": "^2.0.1"
}
I did profiling with stacktrace in android studios, and found that mqt_js is one of the reason which takes more time on every UI clicks. You can check stacktrace report here
Can anybody help me in solving this performance issue.?
Use Flatlist over Scrollview:
initialNumToRender={number}
prop to Flatlist, as it will show only those components which are visible on screen and detach the other componentsUse PureComponent in Flatlist renderItem (In your case it will Each Card), so that they will only render whenever their props get changed.
Check whether your component is re-rendering again and again in order to test put console either in render() or in ComponentWillRecieveProps and if this is happening then use ShouldComponentUpdate.
Remove console.log from render() and ComponentWillRecieveProps.
Make these changes and you see your performance is much better than before.
There can be various reasons which makes the react-native app slower. I would suggest the following key points that can help:
dumb components
overclass components
wherever possible.redux
, it is a powerful state management tool that can provide you the best code, if implemented properly.react-monocole
andappr
. Guide to react-monocole.This is a very broad and opinion based question, but I'll try to highlight the
most common points
and suggestions based on theprofiler
you have listed.Looking at your stack trace, the main problem lies with the
UI Thread
inside your package name iecom.fitspot.app.debug
.As mentioned here.
Once the boundary interval is set to
16ms
, then you can see that themqt_js
or theJS Thread
is taking far longer than16ms
for one cycle, meaning yourJS Thread
is running constantly.In the current
profiler
, it is unclear what processes are executed in yourJS Thread
, therefore it is clear that the problem lies mainly in yourJS Code
and not theUI Thread
.There are multiple ways to make the
react-native
app faster which is well documented in this page. Here's a basic gist to the same.dev=true
, you can disable them across the app for a better performance.Remove all the
console.log
statements from your app, as it causes abottleneck
on the JS Thread. You can use this plugin to remove all theconsole*
statements as mentioned here, in your .babelrc files asYou need to
componentize
your project structure, and usePure Components
, to rely onprops
andstate
only, useimmutable data structures
for faster comparisons.For the
slower navigation transitions
, you might want to check thenavigation library
code, since mostly they have atimeout
fordefault transitions
. As a workaround you may consider building your owntransitioner
.If you're using
Animations
in your codebase, you might consider settingnativeDriver=true
, which would reduce the load on yourJS thread
. Here's a well explained example.You also might want to check the Profiling, to check the
JS Thead
and theMain Thread
operations, well explained on this page.Other stuff includes, not
requiring/importing
the module, which is not necessary, importing onlyclasses
required, and not thewhole component
.Also , you dont need
external libraries
to makesimple UI components
, since their performance is much slower than the native elements ofreact-native
. You may consider usingstyled-components
to componentize yourUI
If
mqt_js
is the main cause of performance issue, that means in every click, the JS thread of your app has too many things to do at once. Communication between JS business logic and underlay native realm is done asynchronously, the more actions need to be finished in JS side when a button is pressed, the slower the app will be.Answer given by Pritish Vaidya already hits the nail on the head. I just want to include 1 more point about the usage of
redux
in your app. If your app's data flow is mainly done usingredux
then you can check for following things:If there are too many redux actions happening on each clicking event, try to remove unnecessary ones or prioritise actions triggering important animations first, then triggering other actions once new RN components finished rendering. You can see which actions are bottomneck ones by
redux-logger
.Break components listening to redux's store into smaller ones, with each listening to a different part of the store. So if redux's store is updated, only a small group of components should be rerendered instead of everything.
Use memoized selectors to deal with frequently updated data. reselect can help you in this case.
First of all you should run your app not in DEBUG. On android it is done by changing
MainApplication
method:and making bundle:
As for the code, here are some advices for optimization react-native:
response.json()
orJSON.stringify
) blocks js thread, so all JS animations and handlers (such asonScroll
andonPress
, and of courserender
method) suffer from this. Try to load only what you need to show.useNativeDriver: true
parameter) where it is possible, and try not to useonScroll
.render
methods and try to make the call of these methods as rare as possible. It is called when component's props or state changed.PureComponent
works and try to use it where necessary. But keep in mind that it also can slow the app down if not used correctly.StyleSheet
for styles, it cashes them and replaces with style id (integer).Bad:
Good:
Bad:
Good:
Object
andSet
instead ofArray
where it is possible. Use pagination when you need to load big amounts of data from server / database, leave sorting and other heavy calculations for server.For example if you often need to get objects by id, it is better to use:
instead of usual array: