Multiple Async Calls Updating State
In our app, we have multiple asynchronous calls firing off when it first loads up. Each call is updating the state with the information it retrieves, in turn components are receiving new props and triggering their setup process more than once. The first problem we have is the main container component rendering children before it is done gathering the data the children needs.
To fix this we need to manage when the children are rendered.
Don’t render the children until all of the async calls have finished. But how do we know when all of the calls are finished if they all finish at different times? We could try and manage this by contionously updating our state each time an async call finishes checking to see if it should also set state.setupComplete, but I want to avoid component life cycles and only update state when the setup process is completed, not when part of it is completed. For this scenario, I think Promises are a perfect use case, and the handy Promise.all can resolve all of our calls, and it makes handling failures a breeze too.
We start by creating a Promise for each Async call and passing the Promise’s resolve/reject into our async calls. We then resolve all of the promises at the same time using Promise.all. That returns an array of promises, which we will loop through and assign the data to our newState object. We can use setTimeout and have a 2sec delay to avoid our loading screen from flashing in and out.
Now let’s take a look at the result of Promise.all managing the Loading State.
That is the user experience that we were going for! Okay so we have avoided the flashing screen, and have created an extensible setup process, but what kind of performance gains did we get with these changes?
React Performance Tools
To get started measuring Reactjs performance we will use the Performance Tools supplied to us by the Reactjs Team. To install them run npm install react-addons-perf -D
and before your ReactDOM.render put the following
Now when you run your page and your components have finished rendering, open up the web console and run the following
Here are the results BEFORE we did any refactoring
Here are the results AFTER we implented Promise.all and Loading State
The biggest gains we can see is in the difference in the amount of instances and the amount of time spent on every component. One other thing you will notice that is missing in the second screenshot is the wasted measurements. That is because we are no longer wasting anytime in the components! Thanks to no longer rendering our components until the container is ready. We have created a highly performant and easily mangeable loading state using Promise.all and not rendering our children until they are ready.