TL;DR — Do read the docs of React, React Native and every libraries you are using Using remote Images can be painful: use a library. Some patterns can be harmful, be careful with PureComponents and HOCS. Keep your libraries up to date. Give some love to your app and you users. This article is based on two years of experience building React Native Mobile Apps, available on and . It assumes you already have some experiences with React and or React Native. It is not strictly speaking dedicated to React Native, as some of the advices you will find below apply for a regular React application. It is also not an exhaustive guide to performance: you can apply all advices found here but still have a laggy app. Don't blame us ;-) Nelio iOS Android Nelio is a food delivery startup focusing on Craft Food, currently operating in Paris. When delivering quality good is your business, it impacts all aspects of your company. From the marketing message to your codebase. Basically, everybody here is focused to deliver the best User eXperience. Performance is one of the topic which can change the overall perception of the service you deliver. To be honest, we have sometimes a hard time matching our and our customers expectation on that topic. This articles is based on what we learned so far during this journey. Mistakes that we did, and will not reproduce, or stuff that we learnt and actions that we took in responses. React and React-Native Performance Being a React developer for the last 4 years, all I can say is that I love it. I was more than happy when joining this React Native project and it matched what I expected in terms of learning curve: Having the same framework make it really easy to start developing your first components, but later on you will need to get a deeper understanding of React Native. Just as being an advanced React Web developer requires you to have an understanding of what is going on in the browser ;-) Regarding, performance in React Native, this is the same: Everything you know about React performance will apply in a React Native application That being said, probably the first next step is to jump to and later on . These are great resources that I will not spend anytime copy-paste or rewrite here ;-) I will rather focus on specific patterns that we put in places or decided to avoid in order to improve performances. React performance doc React Native performance doc I will also not spend any time arguing whether React Native is fast enough or not, whether you should move to flutter or go fully native. There are some great React Native Apps out-there. Here is how we try to be one of them. Do provide UI Feedback Performance is mainly about perception rather than measuring precisely how long a function take time to complete. More important that , you should ask yourself and how long ? why ? when ?. It is commonly accepted that after a user interaction you should give feedback in 100ms. Keep in mind that this threshold is a barrier that you should not cross. Keep also in mind that . it is never too early to give feedback There are different ways to give feedback to the user. In React Native, a great and simple solution is to use the component on all component which accept user interactions. This will give feedback to the user during the interaction and is a great way to indicate that something will occur after the interaction. TouchableOpacity If the click lead to opening a new screen, then you should . Usually a good approach is to open your new screen as soon as possible, render the content that you already have, and display a loader and/or some placeholder component while the content is loading. This is a technic also called spend some time thinking about your data loading Skeleton Screens . If your click lead to something else, such as adding an item to your cart, to favorites, or post a chat message , this very often will include a remote API call. In that case, you should when possible — which is most of the time — . This pattern is called and is also wide spread across the industry. act as if the endpoint did already respond successfully Optimistic UI At Nelio we are using GraphQL with ReactApollo. ReactApollo with the parameter has a great solution to implement this pattern. This can also be done in different manners when using redux. optimisticResponse Images A big topic regarding performance and usability of your React Native apps is image. Coming from a web background, it was for me a bit of a surprise. When you think about it, the browser are doing a huge job dealing with images, speaking of downloading, caching, decoding, scaling and displaying them: all that happening in a streamed way. Do use an Image Caching solution React Native code offers an component, which does a great job at displaying a single image, but has some issues when dealing with a lots of them. Specifically, we had some flickering issues, and also when too many images are loaded in our apps, at some points, they just stop loading. Image We switch to , and it seems we are not the only one. react-native-fast-image Recently react-native-fast-image was downloaded 12% as often a react-native on NPM registry which is almost as Expo Do load images the size you need them React-native-fast-image solved lots of issues we had, but we still had some random crashes in our app that we noticed was linked to some images. After a quick check, we noticed that we asked our app to download, cache, and scale tens of Images, each weighing several hundred KiloBytes. We tried initially to solve this problem by putting some hard limit to images upload, but we were not happy with this solution. In any case, , as this put lots of pressure on the device. A good solution is to do a big part of the job not on the device but before. be careful about the amount and size of the images your are loading An image resized to specific dimensions with cloudImg with the following URL https://acoigzuuen.cloudimg.io/crop/640x360/q95/_s3_nelio_/kaviari-3384d944c6f8418679baee23-1523374450958.jpeg Even if you don't have memory issues with images, it is still a good idea to size your image in the exact dimension you will display them. This will put less pressure on your user device. We recently switch to use an Images Scaling CDN solution which would allows us to download images scaled precisely at the size we would display it. For the record we opted for , and are currently very happy with it. It allow us to request an image on the fly with specific dimension. For a quick implementation with opted-in for a change of our GraphQL resolvers to translate to images URL to the cloudImage one. This change can also be done client side. CloudImage is the solution we went for, for could have used or hosting an open source solution such as or . CloudImage Cloudinary imgProxy Thumbor Do use Pure Components wisely As said previously, React Native apps are before and after all React apps. Most advices which are good for React apps are good for React Native apps. Probably the most popular advices around React performances concerns the use or not of PureComponent (and/or ). Long story short, useless re-render in React is usually not an issue but can become one on complex application. PureComponent is a way to prevent a component to re-render when his props did not changed. More precisely it implements it implements by doing a shallow comparison of props. React.memo() shouldComponentUpdate Some people think it is a good pattern to use PureComponent by default when implementing a new Component. My advice is to always keep in mind that it can be more harmful than helpful. This is really good example . of Evil Premature Optimization If you need/really want to reduce re-render keep in mind, in that case, when instancing a component, you should . not create any props of that PureComponent in your parent render method Don't create any new props at render time when using a pure component The two main uses cases when giving props are providing new objects and new functions. The upper example also show providing a child Component as Children Props, but if you go beyond JSX, at the end, it it just a regular JS object. Regarding objects, also keep in mind that arrays are objects. When switching your component to a more functional style, be always aware that most functional function, which are in themselves pure, create new references. Once again, don't call theses functions at render time. Also avoid pitfalls when going functional Another pattern that you might use a lot when using React-Native are : providing as props a function that return a component. From a props point of view, a render props is just a regular function provided as props, and so the general advice apply: Don't create renderProps at runtime. renderProps Here at Nelio we don't use yet React Hooks which you will need to check if you haven't. Hooks shipped in React Native 0.59, and there will be a dedicated section about it below. What we use instead is , from whose hooks have been greatly inspired. recompose Recompose, thanks to Pure , withHandlers and withPropsOnChange has proven for us to be a great utility at helping keeping our code base clean and improve performance. Don't use HOCs on the fly When you application becomes complex and you want share some common pattern across your component, it is not rare to use . High Order Components Using High Order Component is rather a good practice even if this sometimes can be arguable as it increase indirection. It can though increases the complexity of your code comprehension. Don't instance HOC at render What you should really be careful is . The reason why you don't want to do that is that you are effectively creating a new component. React can't know that this is effectively the same component as before (as this is indeed not). This put lots of pressure on the reconciliation algorithm. More than that, it also force React to run all , on the whole tree. not instance any High Order Component on the fly, specifically during a render method lifecycle method Maybe all of this is really obvious to you. Maybe you think this would be really dumb to do so, and even ask yourself why on earth did we think at some point it could be a good idea. If so, you can have a look at our as we are always eager to learn from the best. currently open position I can remember one case where we had this bad pattern, noticed it and solved it. Basically this happened when we mixed the used of and . As Apollo user, we use in most places to fetch data from our endpoint. Because our code style is to use recompose when possible, the initial implementation was wrapping the Apollo Query component in a HOC. This works great for all query where you don't need dynamic variables, but failed otherwise, as there is . The way we implemented this originally was wrong. We later identifier two ways to improve that. The first one was to accept to not use Recompose HOC here, and just do a regular Component using a more classical implementation. The second one, that we choose, was to switch to , which is to match our usage. RenderProps High Order Components Apollo Query Component fromRenderProps no way to give specific props to your render props component Apollo graphQL HOC documented Another usage that I can imagine is if you need to instance a High Order Component based on props that you received. I created a that show such case. We had in our codebase something that was close from this pattern. After some thinking, we get rid of it by either by not using HOC in those places, and replace it by renderProps or directly providing the Component as props. small example Do use another pattern such as Children, renderProps, or Component as Props Don't implement bulk reducers If you are not using GraphQL, chances are you are using . Here we are using both, but I don't recommend it for most cases. redux If you are not using redux with and/or , or at some point writing yourself your reducers, please be careful to . If you followed attentively you are already aware of this point, but if you are not, then read it again ;-) normalizr rematch always mutate only the objects that you need to Redux basic tutorial If you are like us and sometime too eager to code, then maybe when refetching a list of item from the network, and saving it to your reducer — even in a normalized way — you naïvely do : <a href="https://medium.com/media/3d898468db6f5adc84804d660cd84d87/href">https://medium.com/media/3d898468db6f5adc84804d660cd84d87/href</a> If doing so and having some performances issues while rendering a list of items which can be refreshed in the background, then what you will want to do is update your store only when needed. More precisely : if an items as the same value as before, then you probably don't need to save a new reference for it in redux. Updating reference in your store, will create useless render which by the end will produce the same components. only update references which need to be Don't naively share Selectors If using redux, you are using mapStateToProps functions in your connect() call. As your application grow, and your mapStateToProps complexity increase, then you might notice that some of the computation that you do in your mapStateToProps become heavy. You might also notice that you are sometimes re-rendering too much, which might seems counter intuitive as connect implements his . own props shallow comparison The issue here is basically the same than with pureComponent. If every time you render your parent component you give new props to a pureComponent, it will need to re-render. What you want do here is keep the prevProps if the behavior of your component will be the same. Once this is correctly understood, then is a great solution to overcome this issue. This once again introduce a little boilerplate but this is definitely worth-it. reselect But be careful, . This is specially the case when you share your reducers in different places of you app, or shared across different instances of the same component. The problem here is that reselect selectors are basically memoized method whose cache has with limit of one. Reselect documentation has a dedicated section concerning and provide a pattern to overcome it. Basically it consists of creating new selectors for each instance of the component. Others library such as solves this issue differently. a bad use of reselect can also introduce new performance issue shared selectors re-reselect In any case, you should be really careful about this when you start to share you selector across Components or different instances of the same component. Going further Delivering a lag free experience on all smartphones is not a one time tasks, but as often with Software Development, a continuous quest. You will find below some improvements that we are currently considering. Use React Native 0.59 As said previously, RN0.59 bring React hooks to React Native. Using hooks should allow us to switch away from recompose, which is not developed anymore. Moreover, React Native 0.59 bring to Android devices an upgraded version of , which have not been updated in a while. This update bring a performance gain of about 25% and JavaScriptCore 64 bits supports which will be mandatory on Google Play store starting August 1, 2019 . Experiment with FlatList Options When rendering a list of elements, you should always use a component based on a , such as a or a . Depending of the number of items of your list, the complexity of your component and their dimensions, you probably want spend some time tweaking their props, as lots of them will have a direct impact on Performance. VirtualizedList FlatList SectionList Use Tool to detect your performance issue When trying to understand performance issues, you want try to understand how much time a component isMounting or rendering. has been a great help at understanding sources of lags. React Profiler Something that we haven't used yet but can be useful when trying to find sources of responsiveness in your app, is , as explained . The Queue is the communication proxy channel between the JS part of you app and the Native Part. spying the queue here Your interface might be something half reactive : For example the scroll view or the touchable opacity work, but then the JS handler that you wrote are not triggered. In that case it means that the native code is executed, but not the JS. Spying if the queue is super busy is probably a good step to understand what is the source of your issue. Thanks Woo, congrats for reading until there. Any personal tips to share ? Don't be shy and comment ;-) Any question you still have ? Please put it there, and I'll do my best to answer.