Tips for Upgrading to React 16 and React Router 4
I recently had the pleasure of upgrading a large codebase to React 16 and React Router 4. Pleasure is perhaps an exaggeration. The upgrade process went smoother than others I've encountered, but it was pretty painful nonetheless.
Here are a few things I learned along the way that may very well help you during your upgrade process.
First, though, why upgrade? You have a feature to ship and upgrading now will just slow you down, especially if you switch over to React Router 4, whose API has totally changed!
In general, keeping your libraries up to date will result in less pain later on because you won't have to deal with upgrading under the gun due to seemingly sudden deprecations. This recently bit our team when the GitHub API changed a bit and we hadn't upgraded our Octokit wrapper in years. I also did the upgrade for that gem and because we did a lot of custom work with Octokit, it was extremely difficult to decipher what exactly was going on. That coupled with the lack of good unit and integration tests made it somewhat of a nightmare for me. Luckily, I did extensive testing and wrote a bunch of unit tests, so when I finally shipped the upgrade, I didn't break anything else! Hooray.
So I'm a fan of keeping things as up to date as possible.
Another benefit in particular for React 16 is that it adds a few really nice features, including the ability to return an array of elements from a render method, better error handling and boundaries, and a reduced file size. Those all sound sweet, yeah? Sweet enough to warrant an upgrade.
There are trade-offs, of course, and you might not want to update all the time, but at least being aware of changes in your dependencies is pretty important.
Okay, so that brings us to React 16.
I upgraded the entire codebase to React 16 and React Router 4 over the course of a week. Initially, I did a small spike to see just how hard it would be to upgrade React, and it turns out it wouldn't be that hard.
Here are the things I had to tackle:
- Replace the deprecated
React.createClasssyntax with the new
- Bind all the callbacks in those components
- Rewrite components being rendered by a Router component
Rewriting wasn't terrible, but
because we don't have a lot of front-end tests, I had to do a lot of manual
user testing to make sure I didn't take down the whole site. Also, major
props to my former colleague, Seiji, for rewriting a bunch of components to
prop-types library before he left the team. Major. Kudos.
Fortunately, after I did ship it to production, only a few things broke, and I was able to resolve them quickly after the fact.
Anyway, here are the tips for real.
- Do a small spike before you dive in
- Write some tests if you don't have adequate coverage
- Try to chunk the upgrade. For React, I could have rewritten the components in smaller chunks rather than shipping one 7,000 line PR. That was not wise. I could have done one app at a time since the API didn't change a lot.
- Write some more tests. And do a lot of manual testing.
- Don't change all your
componentDidMounts without checking how your different apps are handling a loading state. Made that mistake once. Won't do that again. (Some people have talked about eventually deprecated that lifecycle hook since it's nearly the same as the constructor.)
I think that's all for now. I wish I had written more tests, but yeah, I know, it's hard. I'm writing this in the hopes that the next time I have to upgrade something, I heed my own advice.