How State Management Works in React Native vs React
State Management in React Native has similar options to React.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo 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.
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.
[00:00 - 00:10] React provides a way to do state management at a component level. And depending upon what we have chosen to build, that is a class component or a functional component, the implementation can vary.
[00:11 - 00:22] We'll look at both of these in this particular lesson. What we'll do is we'll implement the search screen, and we'll do a class based implementation and see how it manages state for its own view.
[00:23 - 00:27] And we'll also do a functional implementation for the same. So let's get started.
[00:28 - 00:39] States are basically controlled in any component in React, either through props or the state variable that the class component has. Now props don't change over the lifecycle of a particular component.
[00:40 - 00:47] They are basically the variables or the values that are passed through to the component as inputs. And states are what we declare internally in a class.
[00:48 - 00:56] A very simple example can be that features declare a state variable. This is already available if we extend the class by react.pure component or a component.
[00:57 - 01:03] And then we can declare anything over here like we have a double. And then in the redder function, we pull the variable from the state.
[01:04 - 01:14] Then based on that, we assign a condition to render something. And how we change the value of the state is there's an input function that's called this.setState.
[01:15 - 01:22] And we just pass the value to the variable that needs to be changed. As soon as this happens, the function will re-render itself.
[01:23 - 01:30] So that is quite straightforward, right? We just have a state variable and we assign whatever we want to and whatever we want the component to watch for.
[01:31 - 01:40] And whenever that changes, the component will re-render. So where it gets a little complicated is if we go back to the lifecycle of any particular React component.
[01:41 - 01:55] So now we should not be doing any set state in the render phase of the component. What that means is that if we do a set state inside a constructor or other red der function that will make the component render infinitely.
[01:56 - 02:02] The reason for that is when we do a set state, the render function is called. Since the state of the particular component has been updated.
[02:03 - 02:11] So that makes it an infinite loop. Now we can also do set state inside a component did update, but we need to add an if condition.
[02:12 - 02:19] Component did update is called just after the render function is called. Anytime, whether it's the first time or the subsequent times.
[02:20 - 02:36] Now, if we do a set state inside that without an if condition, what that basically means is that the lifecycle will keep going on in a loop. As the set state will call the render function and after the render function, the component date update will get called and it will keep going on and on.
[02:37 - 02:40] So that's where we need to be a little careful about. Otherwise, it's a pretty simple implementation.
[02:41 - 02:47] So let's look at that. Let's try to save the values that we enter over here as recent searches.
[02:48 - 02:54] What we can do is we can simply declare a state inside our constructor. So we'll just say this dot state.
[02:55 - 03:12] We already have that variable and we'll say recent searches and we can declare that as an empty array. And whenever a user enters something and click submit, we'll see if that as a research search.
[03:13 - 03:20] Going forward, we also might want to save that in a permanent storage in the app. We'll look at that in the AC storage module.
[03:21 - 03:31] Now let's say that we wanted to save a user's recent searches on the server side, right? And whenever we load the search page, we want to fetch that data.
[03:32 - 03:39] So component date mount is the best place to fetch any server side data. This is called immediately after the first render.
[03:40 - 03:57] And if you want to make a network call to get a data for that particular screen , this is the best place to move that. And right here, what we can do is once we make the call, we can also do this dot state and that will trigger the tree render.
[03:58 - 04:06] Now what that also means is that the render function is initially called without that network call. So the function needs to also handle that scenario.
[04:07 - 04:16] Let's say that the page is trying to render recent searches, but it will be called before the network call. We need to handle the scenario where we don't have the research searches from the network data yet.
[04:17 - 04:25] Next, let's try to save this recent searches. So what we'll do is we have this input box.
[04:26 - 04:37] And as soon as we click submit, we'll save that to the recent searches and display it on the page below. So it is to that for that we need to add one property to the input box.
[04:38 - 04:51] Let's go to the input box. Now, we want to save the value whenever the user clicks, go or submit in that.
[04:52 - 05:07] So let's say that we type speakers. And when a user clicks return from there, then we want to save that.
[05:08 - 05:25] So how we can do that is the text input takes a property that's called on submit, editing. This basically is like the submit on a form and it's called after user presses a return or whatever the button is there.
[05:26 - 05:40] Let's declare that as props for this and expose it. So we'll say on submit and let's declare the type.
[05:41 - 05:51] On submit event, let's make it non mandatory. On submit.
[05:52 - 06:03] Now what this gives away is a native event. So we'll declare that type.
[06:04 - 06:26] So if we click on submit editing, we'll see that it expects a. It provides a native synthetic event, text input.
[06:27 - 06:38] We can simply copy this over. And that should work for us.
[06:39 - 06:57] So now we'll just expose that. We will say.
[06:58 - 07:07] On submit. And we'll pass that now our text input also supports passing in on submit.
[07:08 - 07:15] So that is great. Let's go back to the text input and let's pass that we can copy those types from there.
[07:16 - 07:19] And we can pass that to. On submit.
[07:20 - 07:48] And we can pass that to. On submit.
[07:49 - 08:02] Now we go back to the search page and we go to the header component and we say that we need a. The search input now takes an on submit.
[08:03 - 08:19] Now let's declare a handler for that. And what we get is a dev event.
[08:20 - 08:52] And the value will be inside a dev event dot text. So let's declare native.
[08:53 - 09:00] Send it a event and. Text input.
[09:01 - 09:17] Submit event data. Now what I've also done is I have launched flipper.
[09:18 - 09:20] This is a debugger tool. So it's quite simple to use.
[09:21 - 09:30] We just need to install it and as soon as we launch it, if the Metro bundle is running with an app, it will automatically pick that up. Now it's useful for a few things like looking at the logs.
[09:31 - 09:37] This is the log that we have that we can also see in the Metrobundler. It's same running drawer, home and search.
[09:38 - 09:42] But this is a more cleaner interface and reactivity. But also does this.
[09:43 - 09:48] But apart from this, it also tells us the layout. So we'll look at how to use paper in detail in the upcoming modules.
[09:49 - 09:53] For now, we'll interested in the logs. So we'll use it for that.
[09:54 - 10:02] Now on submit, we have our text. We'll save that and should also save this.
[10:03 - 10:14] Once we refresh our app and we press enter. What we get is the text.
[10:15 - 10:19] Now what we need to do is we need to save that in the state. Now we have two options here.
[10:20 - 10:35] Either we ask the header to save the values with itself, all the recent searches or we can pass this value to the parent and ask them to do whatever they want with that. Now what we'll do here is as soon as someone presses an enter, we'll make a request, a network request.
[10:36 - 10:43] We'll do that in the module that we'll talk about making API calls. We'll make a network request for that and show the results over here.
[10:44 - 10:50] But we also want to save that as recent searches. How we can do that is let's pass that to the parent page for now.
[10:51 - 11:10] So how we can do that is we'll declare the on submit method. On submit and we can say on submit event and let's just copy that over.
[11:11 - 11:26] So now on pressing the return, we'll pass this value to the parent component. Let's comment this out.
[11:27 - 11:36] I probably will copy this over to the parent component. So we'll go to search and where we are passing the header, we'll say.
[11:37 - 12:10] [ Silence ] And we'll pass the submit to the header. [ Silence ] Now we have the value over here.
[12:11 - 12:27] What we can do is we say this dot set state and then we need to just pass it to the recent searches. So for that, we first get the recent searches.
[12:28 - 12:45] [ Silence ] From the state. [ Silence ] Okay, we need to declare it.
[12:46 - 12:59] So we'll say recent searches and it can be an area of string. Let's keep it simple for now.
[13:00 - 13:18] We'll say recent searches and we'll say recent searches dot push and we'll push the value that we are getting. And we'll set the recent searches to recent searches.
[13:19 - 13:32] So as soon as we do that, we should have the value in the. So let's save that and let's also see if the value is being set or not.
[13:33 - 13:45] So set state, it takes a second function and that basically is a callback. Once the application is done setting the value of this particular variable, it will give a callback where we can execute whatever we want to.
[13:46 - 13:59] So right here, what we can do is we can do console dot log and if we check the value this dot state dot recent searches. We will see that whatever type is getting saved into this.
[14:00 - 14:15] We'll say speakers and we press enter and we see this dot recent searches as speakers. So now let's also go and search for something else that say headphones and now it has speakers and headphones.
[14:16 - 14:23] So that's quite simple, right? And remember every time we are doing a set state, it's also again calling the render function.
[14:24 - 14:39] And we can put a console to check that. We will save that and now as soon as the view was loaded, render was called and we say speakers.
[14:40 - 14:51] It is doing that render is called and then the callback happens. So we can clearly see the life cycle over here and similarly for headphones.
[14:52 - 15:01] Now we have the values all we need to do is we need to display it. We will say that in the function will say const.
[15:02 - 15:12] We'll get this from state. Now remember initially this will not have any values and just an empty array.
[15:13 - 15:24] So if you want to display this as a list, we want to put a check on that. We'll say recent searches dot length greater than zero.
[15:25 - 15:33] Only then do you render this particular block. So we'll say recent searches dot map.
[15:34 - 15:46] And now this is the search term. Let's just do a simple view on this one.
[15:47 - 16:05] This is just to demonstrate. And we'll say search, let's save it and we'll do a ctext.
[16:06 - 16:12] So we'll use a standard text. And we do save.
[16:13 - 16:26] Now let's say speakers and we can see the speakers there. And let's do headphones and we get the headphones there.
[16:27 - 16:30] This can have a title. We could probably add a section title for that.
[16:31 - 16:45] Let's just do section title and we can say title equals. Recent searches.
[16:46 - 17:01] Now see as soon as that time you will refresh, we lose it because this is getting stored in the corporate state. We do speakers and we do headphones.
[17:02 - 17:19] So next let's look at the other lifecycle events of a class. As I mentioned earlier, component did not is great for making any network calls or doing any side effects that we want, like pitching data from a sync storage or API or something else.
[17:20 - 17:26] And we can do a set state over here. Should component update should be avoided.
[17:27 - 17:38] What this basically requires is it requires a Boolean return. What this is going to provide us is with the next prop and the previous props and we can compare them and see if the values have changed or not.
[17:39 - 17:48] And then avoid additional vendors. This should mostly be avoided and the recommendation is to use a react pure component class.
[17:49 - 18:08] And as soon as we do that, we'll also see a warning on the UI that says search has a method that's called should component update and it should not be used with a pure component. So what pure component does in react is basically does a shallow comparison of the attributes of the props in the state.
[18:09 - 18:17] And that's a great way to avoid any additional renders that are not required. Next, we also have component did update.
[18:18 - 18:22] This is called after the render function. We're going to make network calls over here.
[18:23 - 18:42] If you feel that the props that have been passed to us require a certain update to the UI, like for example, we get a different user ID and we want to fetch the data for that. We can do that over here and we can set state over here to not just one other condition is that this function is called after every render function.
[18:43 - 18:55] So it is a mandatory practice to add an if condition to it because if we don't do that component update is called after the render function and then the set state will trigger again or enter. So we'll end up in a loop.
[18:56 - 19:07] Remember, if you want to use component did update to compare any props of previous states, we have to use an if condition. Apart from that, we also have the component will unmount.
[19:08 - 19:15] And this is called just before the view is unmounted. Generally, there's not much that we can do here.
[19:16 - 19:30] If we do a set state, it's not going to matter because the view is already getting unmounted. One thing that it's useful for is cleaning up any methods such as invalidating any timers or events that we have subscribed to or canceling any network request.
[19:31 - 19:41] So that's the state management with the class. Next, let's look at how we can achieve quite a similar functionality with functional components.
[19:42 - 19:52] Next, let's look at implementing the same using the functional component and we 'll be using hopes for that. So, let's look at how we do it with the functional component.
[19:53 - 20:00] There are a lot of different types of hooks. We'll look at the use state hook and the use state hook.
[20:01 - 20:09] So, let's look at how we do it with the functional component. There are a lot of different types of hooks.
[20:10 - 20:25] We'll look at the use state hook and the use effect hook. Those two help us achieve the same functionality and the same lifecycle that we had for a class component and covered most of the use cases.
[20:26 - 20:53] And it's generally a good idea to build at least most of them as functional components and use hooks as much as possible. Though in my practical experience, when the view tends to get a lot more complicated, say a product details page might not be that complicated a scenario, but something like a cart page or a checkout summary page that shows all the different details of the different steps that are used as taken so far.
[20:54 - 21:07] I have found implementing a class a much easier solution. Now we had data that was coming from the previous screen, but we also needed to handle the use case where someone clicked a deep link and landed the page directly.
[21:08 - 21:26] Now the data that needs to be initialized for that page is either passed as props or fetched from an API based on where they are really being requested from. In practical scenarios, some of these screens tend to get complicated and having a class implementation is not a bad idea.
[21:27 - 21:37] So if you see yourself in planning towards a class implementation, then that's totally fine. Let's look at the functional components.
[21:38 - 21:45] We had a variable called recent searches that were declared in state. Let's declare that using a hook over here.
[21:46 - 22:24] So what we'll do is we'll first convert this to a regular function and we'll say const will use use state hook because we want to declare it with an initial value and the initial value is going to be at empty array. So what did I just do here?
[22:25 - 22:32] Basically whenever we use a use state hook, it provides these two variables. The first one is a variable that will have the actual value.
[22:33 - 22:40] So it can be anything that we want. And the second one is basically a set state function specifically for that variable.
[22:41 - 22:53] If we look at a class, we had a set state and we did a set state on a variable. So we said this dot set state and then we pass the variable that we wanted to set.
[22:54 - 23:01] In this case, we don't need to do that. We just do a set recent searches and whatever we've passed to this is going to set to the recent searches.
[23:02 - 23:10] That's how we are declaring a state in a functional component. And we'll go ahead and use that.
[23:11 - 23:24] Let's also go ahead and pass the on submit function to the header. We'll say on submit.
[23:25 - 23:34] And I'll just copy over the function. It's going to remain quite same.
[23:35 - 23:36] And we'll not need most of it. So let's just remove that.
[23:37 - 23:43] We can simply set the value using this particular function that we have. And we just need to pass the value that we need to set.
[23:44 - 23:55] So what we'll do is first we'll use this spread operator for passing the existing values that this has. And we'll also additionally pass the new value to it.
[23:56 - 24:06] And this should set the value of recent searches to the new value that we want. Okay, we did not initialize the area with any value.
[24:07 - 24:18] So we need to tell the use state that what kind of value are we expecting. So we'll just say that we are expecting an area of string and that should fix it.
[24:19 - 24:37] Okay, once we save, we'll get the value in recent searches. Next, I think we can also copy over the rendering part.
[24:38 - 24:41] Let's save that. And we have the recent searches.
[24:42 - 24:55] Let's say speakers, we save that, we get the value and let's say headphones, we save that and we get the value. So that was quite a simple implementation with functional components, right?
[24:56 - 25:08] And if we look at it, it's much simpler than the classes. But like I said, for a really complex scenario, I found the classes to be more manageable than the functional components.
[25:09 - 25:24] Next, let's look at achieving the same lifecycle that we have of a class component in a functional component. So how do we achieve the same functionality of a class that is done using the use effect hook.
[25:25 - 25:31] So use effective to get place for doing any side effects like we had in component dead mount. So this is a good place to make the API calls.
[25:32 - 25:40] Let's say we want to fetch a data for a particular screen or get some data from the async storage. Now there are a few things to consider over here.
[25:41 - 25:49] The first is this additional parameter. Now let's say that we declare a use effect hook without passing any additional parameters to it.
[25:50 - 26:06] What that will do is it will execute the use effect hook every time. What that means is it will execute the use effect with the first time the functional component renders and also any time that there is a change in value of any of its variable using one of the set state variables.
[26:07 - 26:24] The use effect hook takes a second argument as the set of variables that it needs to watch for to trigger any changes to the component. Let's say that we are dependent on data or set data and we want to re-enter the view whenever those variables change.
[26:25 - 26:39] We should pass those as an array argument to the use effect. And what the use effect hook will do is whenever there is a change in any of the values of the past variables, it will trigger whatever is inside the use effect.
[26:40 - 26:49] If you pass an empty array, the use effect will run just one time. What that means is we are saying that we don't want to watch for any particular variable.
[26:50 - 27:04] So now that use effect hook effectively becomes a component dead mount, which basically runs just once. If you remember from the class implementation, the component dead mount is called only one time whenever the component is mounted.
[27:05 - 27:17] So if you pass an empty array to use effect, we'll basically achieve that functionality. Now if you pass an array of values, the use effect will be called for any change in those particular values.
[27:18 - 27:33] So that is equivalent to calling the set state only variable in the class implementation. Now what use effect also allows is if we return a function from a use effect, this function will get called whenever the particular component is getting un mounted.
[27:34 - 27:47] So basically this will act as the component will unmount in a class implementation. So as you can see, use effect provides a different lifecycle events that we saw in a class implementation.
[27:48 - 27:55] Let's go ahead and test that. Let's just copy this over and we'll say that we want to use a use effect.
[27:56 - 28:11] So we'll say use effect and what we want to do is for recent searches, we want to watch over recent searches. And let's do this.
[28:12 - 28:16] We already had some recent searches that we wanted to fetch for that user. We will set that over here.
[28:17 - 28:24] Let's mark that. We will set set recent searches and we'll initialize this with some value saying.
[28:25 - 28:42] We'll call that and we are also pre-turding a function from that. We are simply doing an console lock for unmounting.
[28:43 - 28:47] So let's save that and let's go back. Let's clear this.
[28:48 - 28:57] And let's reload the view. So we'll go to logs.
[28:58 - 29:08] We'll see that we already have the render console over here. The reason for that is in reactative navigation.
[29:09 - 29:22] All the tabs are initialized as soon as the app is loaded. So basically when we open the app, the home tab, the search tab, the cart and as many tabs as we have, all of them gets initialized.
[29:23 - 29:35] So that's how we see the render over here and we only see that once. So that basically achieves our component did mount and we already had speakers set to it.
[29:36 - 29:54] So we see the speakers over there and let's say we want to add headphones to it and we can add headphones. So as we can see using a functional component, we can achieve quite similar functionality, what we had for class.
[29:55 - 30:04] A functional component also keeps things simple. And if you look at the overall implementation, it seems much more concise.
[30:05 - 30:20] The hooks were introduced not just because Facebook supports functional programming, but there's another great use case for that. And that is let's say that we have different views and we see ourselves rewriting a particular logic again and again.
[30:21 - 30:33] Like let's say that we had this logic to save the recent searches and then we were also going to save this in some kind of an async storage or a network. And this was a more complex logic.
[30:34 - 30:44] And in some other view, we were again finding ourselves doing the same thing again and again. We can also define our custom hooks and we can write our entire logic inside that.
[30:45 - 30:53] So this is a sample from the official docs. What we can do is we can write our entire logic and then we can simply reuse that hook in different views.
[30:54 - 31:01] That was difficult to achieve in a class implementation. Custom hooks allows us to do that quite easily.
[31:02 - 31:13] So we can define the view logic, not exactly a business logic and reuse those as hooks in different views. Just one thing to remember is that always take care of this second argument.
[31:14 - 31:18] Just be wary of that. Thank you and I'll see you in the next module.
[31:19 - 31:23] module.