Optimize Perceived Performance With React Native Lifecycle

Learn about the screen lifecycle, and customize the app bar and the back button. We will also look at perceived load time and how to manage it.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the The newline Guide to React Native for JavaScript Developers using TypeScript course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to The newline Guide to React Native for JavaScript Developers using TypeScript, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course The newline Guide to React Native for JavaScript Developers using TypeScript

The screens are two apps, what pages are to a website. So there is one major difference. The screens of our app that are on stack are all kept in memory. And pressing the back button will take us to the previous state the screen wasn 't. Rather than the view being re-rendered, unlike web where every visit is a re- render. Now what that means is let's say that we have this page open and I click this link. It opens up this page. Now when I go back, although that page did load quite fast, the entire layout was still re- calculated and re-painted. Unlike an app where ultimately unless we changed the props or the state, the screen doesn't re-render, this is quite important. Let's say that we are on a particular screen that displays the price of a stock or a product. And we go to some other screen and then come back to the same screen. Now on web page, when we come back to the same screen, it makes the API call and the price that you see will most probably be an updated price. Now that is not the case with an app. When we come back to a screen after pushing a screen on top of it, the previous screen actually doesn't re-render. It doesn't call any of the life cycle methods. So it shows what it had when the new screen was pushed over it. If all of this is not making a lot of sense, let's just look at the React Native life cycle events and then we'll see what it means. So the screen life cycles events are pretty much similar to what we have in React. So the first is initialization of the constructor. So this is a good place to set the state initially. And this is actually the only place where we can directly set the state by saying this dot state equals something. Then we have our render function. And this is the only method that's actually required in a class component. Now this function should be pure as in there shouldn't be any, we shouldn't update any state or do any side effects in this. In fact, in the entire interface that's a constructor and render, we should not do any set state. After the render function, the component did mount is finally called. And this is a great place to make those API calls and any other side effect that we may require for our view or the screen. We can definitely do set state here and calling this set state will again call the render function. So component and mount is only called once in the entire life cycle when the view is initially mounted. Component did update is called every time we do set state. In component did update, we can also do set state, but just be very that doing a set state in component did update will again call the render function. And we might end up being in a loop. So always encapsulate the set state in this with an if condition to check for specific properties if they have changed only then call the set state function. Next we have our component will unmount. So this is called just before any particular screen is unmounted. A set state doesn't really work here. So doing a set state will actually have no effect. There are a few other phases that we may require sometimes like should component update. So in this particular function, what we can do is we can check the previous state with what has changed and compare the two. And if we think that the change doesn't really require a re-render of the component, then we should simply return false from here. So this component, we should either return a true or false telling the telling react that whether we should update the component or not. This is more of a performance optimization to stop re-renders. Although we should not use it too heavily and relying on pure components or functional components is a better alternative. Similarly, we also have get snapshot before update. So this is a good place to get UI related information. For example, we can read the position of the scroll. And if we want to keep it same or change it depending on the new data, then we can do that right here. So as we saw, these phases are quite similar to react. Now apart from this, reactative navigation also provides two more life cycle functions events. One of them is component did appear. So this is called after component did mount. And what it does is every time the screen appears on the device, this function is called. So what that means is when we do a push screen and we go back, component did mount will not be called, but component did appear will be called every time the screen appears. And similarly, it has a component did disappear function. And it does a very similar job. So let's look into that. Let's add some consoles and we'll just say mount. And let's also declare component did appear. And we'll say appear. So just notice the log over here. Now since the screen refreshed, it said mount. Now just notice what happens when I come back to the screen. So I say push, it says we have gone to some other screen dummy screen. And now we come back and it says appear. Now the mount was not called, but appear was called right. So push and go back. So if you recall the price information example, and now if you wanted to update the price, whenever this screen was presented to the user, you could simply make that call in the component did appear function. And there's one more lifecycle event that's called component will unmount. And this is basically used for clearing up any event handlers you might be listening to. And like for example, if you listen to the back handler or custom event that we are firing from the application, this is the right place to do all the cleanup for the screen before the screen actually unmounts. So that was about lifecycle events for a class component. But what if we were to build a functional component? So for functional component, functional components are like one big render function by default. React introduced hooks in version 16.8. And we use effect is one of those hooks using which we can actually implement something very similar to component did mount and component will unmount. So if we use the use effect hook, anything inside it will be called on render and on every state change. And if the use effect returns a function, the function will be called when the component is unmounted. Now, like I said that whatever we put inside use effect will be called on first render and on every render. But what if we want to do something like component did mount and only call it the first time the component is mounted. So for that use effect accepts a second argument. This is an array and it is an array of values or objects that the component needs to watch for changes to be called again. So if we pass an empty array over here, that means that the particular functional component doesn't need to watch for anything. And this use effect will be called only just once making it work like a component did mount. But let's say that we are setting a particular object or a state object over here and we want to watch it for changes. We could simply pass that over here. And whenever there is a change in that object, the user function will be called again. We look more in detail about hooks in the state management module of this course. Next let's look at accessing data from a screen. Now the most popular ways are either through an application state that can be your Redux or mob backs or some other state management tool that we might be using. The second is react context API. This was also recently introduced. We'll talk about these two in more detail in state management module. Let's talk about the third one, which is pass props as we saw in the navigation setup. When whenever we push a screen, we can pass props to it. It's quite as simple as passing an object and the screens will be able to access that data either from a constructor from the props object. So it's quite as simple as reading the data from props argument or it can also be accessed from the static options attribute. Let's just look at an example of these two. So right here in the home component, when I've actually called it from the navigation navigator, I have passed some prop that says text is this is home. And if you go back to the home component, we can access it again from the props object. So we can just say props dot, let's say text and props dot text. So let's just declare it in state and also in props. And if we just use it in the render function. So we get this is home. So this is quite useful. Let's say we don't want to put something into the state or let's say we have a scenario where we placed an order when and we only need to pass a simple state that the journey was completed. So while going back to the root screen or going back to some other screen, we can simply pass these temporary prop values to the screen that we are opening to be consumed. And that way we don't need to pollute our global context or global application state. We also saw a second way of setting the props. This is provided by reactative navigation. So basically what we can do is we can declare a static function options. And then we can access the props over there. So this is evaluated when the screen is created. So if you want to set something like a screen title, then this is a good place to do it. So this is the dummy screen one, let's go to dummy screen one and let's set that and let's reuse dummy text. So whenever we are calling the dummy screen, let's pass some props. So dummy text is hello from home or let's just say dummy title, let's save it. So let's just push the screen and there we have our title. So let's look at some of the UX best practices. If our screen requires data to render the page, then while that call happens, what the user sees in by default is a blank screen. So that's not a great user experience for our end customers, right? So to avoid rendering a blank screen, there are a few things that we could do. The first is you could pass some data from the previous screen and then render it. We could put in some placeholders. This is a very common practice as you would see in a lot of apps today or we could also do a combination of both. Now remember that what a user sees is a perceived load time, a perceived load time generally tends to be a lot higher than the actual load times. So let's say that a screen took approximately around four seconds to load. The user may feel like it took more than five or six seconds to load and given some time, the recall value of the same may be around eight to 10 seconds. So our goal is to actually reduce the perceived load time. How we can do is how Instagram is doing it here. Now let me just open that up for you. Now let's look at that a little slowly. So as soon as we click the profile, we'll see how the profile icon title and also the profile name are all passed from this current screen right there. It also has the profile name, probably it had the data in the previous screen and for data like post followers and following it has the title there and is probably fetching the data in the background and for images, it still has a placeholder till they are loaded. So this entire process makes the whole thing feel to be loading a much faster, right? Instead of having a three seconds of blank screen, we have some data. So the user doesn't feel that time that really passed in rendering the page. So this is what is a great example of reducing the perceived load time and is also one of the most common matrices that has that's tracked these days instead of actual load time, like the first contentful paint that we have on Google's developer toolbar or the first useful render. So while developing any screen, we should always keep in mind of how we can reduce the perceived load time. So lastly, let's look at the ABAR. They're quite similar on Android and iOS and typically the ABAR has three different components. One is a centered or a left-aligned title and a subtitle. The second is a back button. On iOS, it also supports having additional action items here with the back button. Android doesn't do that and having a set of action buttons on the right. To use them, whenever we're setting the top bar while pushing the screen or to static options, we say that we need right buttons, all have buttons, only for iOS. And we pass in the component that you want to render, it's the registered component and pass props quite similar to what we do for any other component or screen. So let's try that. I've declared a simple, very simple card button. It has touchable opacity and on click, it will take us to the card screen. I've made it configurable over here and it renders the card image. The first step is to render it, register it, sorry. And let's just go ahead and do that. So we'll do, let's name it card button and we'll do it from elements, action buttons. Right? And then just register it. It says to not screens. We need to declare a different set here. So we'll declare action buttons. And let's just do card. And we'll do action buttons. Card we need to import action buttons. Then we say, we pass in the component card. So we have it registered. Now let's go to the navigation or let's go to the router actually and wherever we are pushing the dummy screen, let's also do top bar. And then as we declare our screens, simply declare the right buttons. It takes an array and we will say component name, we pass in the name screens. Or it will be actually be action buttons.card.id. Action button. Card. Let's see what, okay. So we need to pass an ID. For now I'll keep it same and let's save it. Let's go to the app, push screen and there we have a button. And if you want to change it, we can just come back to the router for it. So let's just do that. So pass props and we declare the unclick prop. And we say, so card screen that's right here and it needs the component ID. So we already have it. We pass that and save and let's try that. There. So we can declare as many right buttons as we want. Ideally we would only want a couple of them or maybe three at max. You can also have context menus. They're like drop downs. When you click them, you have more options. You can do that. Or if you want to add some kind of an add to wish list. So this is a great place to do that. The iOS also supports these action buttons on the left. Although Android doesn't. So if you want to maintain some kind of a consistency between the platforms, avoid using it on iOS to the last thing that we can look at is custom pack navigation. That is changing the back button. Now iOS has this small arrow and Android has a complete arrow with that horizontal line. So if you want to make that consistent, we can do that. We can put an image like this. And then the image will show up instead of the default icon that for iOS or Android. Now if you want to do that for the entire app, the best place to do that is in set default options. So that would be index default options. And we just say that top bar bag button and we just let's just copy this. And let's fix the path for it. So it's inside view assets, images and back button.png. It's also add a color to it. Although we want a warning but something like default selected. Let's do it. Let's check. So this back button image is something that I already have in assets. So if you can see that it's something quite small and like this with a little border, let's push 3 and there we have it. We can also change the style quite similar to tab bar items. We can customize it on both the platforms. We have a similar experience. So to summarize in screens, we saw the lifecycle events and we saw that we have two additional events component data peer and continent it is a peer. This is provided by reactative navigation. They're helpful if you're trying to re-render a view when it comes back from a stack from behind a stack. Then we saw how will implement similar lifecycle events in the functional components. Then for accessing data, we'll look into more detail in state management using React context and applications state, bookstore. We saw how to pass fraud between screens and how to access them either in the constructor or in the static options. This is again provided by reactative navigation. A very important best practice for developing screens to have a perceived load time in mind, either by having some placeholders or some data from previous screens or a combination of both. Then how to configure the app bar and how to do a custom back navigation. [BLANK_AUDIO]