Boosting the Order Details Page at Shippo
React performance testing is a hot topic here at Shippo right now, and it’s been paying off for us — we’ve managed to cut load time for the main flows of our web app by 60% with just a few small changes. In this post, we’ll discuss one change that reduced browser painting and rendering time by 50% for our forms using the redux-form library.
One place where we use redux-form is in the entry form for addresses. But our address forms had a problem — for some reason, the input was laggy on some of the fields, and it could take several seconds for typed text to appear.
Our first suspicion was to check for special keyup events on the input fields which could lead to lag, but there were none. We got together as a team to discuss our approach to tackling this issue and we decided to profile the component using the profiler from react-devtools.
Using the profiler, we discovered that one of the components which we included close to our route component was rerendering on every keyup. Then all the child components of this component went through unnecessary reconciliation, which forced the child components to rerender. The user, in turn, experienced input lag while the child components were rerendering.
Further investigation revealed that the one of the props used for feature testing coming from our Redux state mapped through a mapStateToProps function (read more about Redux’s mapStateToProp functions here) was changing every time the user typed.
Here’s where the problem was: the prop was using array.map() to generate a new array and map it to the props. Every time something changed in the Redux state, this array.map() call generated a new array. The component saw that as a prop change and did a reconciliation, leading to a rerender.
useEffect to the Rescue
Once we identified the issue, the next step was to optimize this code. We removed the array.map() call from mapStateToProps and left the Redux state to be directly mapped to the component props.
The mapping code was moved to inside the component and wrapped in a useEffect() hook (read more about useEffect() here) to set a local state variable and update only when the Redux state changes.
With this single change, we reduced the browser painting and rendering time for this component by 50%. And we’re happy to report that our address form is lag-free now.
Access the demo code: React Redux Form optimization