Relatable Code

Back

How to migrate Create-React-App to React version 18

5 min read

Introduction

React just recently came out with a new version of their library: React version 18. I have a few apps that I’ve been maintaining for a while now that we’re bootstrapped with Create-React-App. I’ll go over how to migrate to version 18 and the issues I ran into along the way.

Here you can find the list of changes for React 18.

I also have a small write-up for my thoughts on it here.

Create-React-App migration to React version 18

The actual process of migrating is pretty quick. Let’s install the necessary dependencies:

Bash/Shell
yarn add react react-dom

The team behind create-react-app also came out with version 5.0.1 to help the migration process and make any new apps come with it out of the box:

Bash/Shell
npm install --save --save-exact react-scripts@5.0.1 or yarn add --exact react-scripts@5.0.1

If you’re using Typescript don’t forget to update your types not only for React but for different third-party libraries. A lot have updated their apps.

Bash/Shell
yarn add @types/react @types/react-dom @types/node --dev

Mandatory changes

The first thing we have to do is change how our root node is being rendered by React. The first code block is how it originally looks.

TypeScript
import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root'));

Now we’re going to use the newly added createRoot function:

TypeScript
import { createRoot } from 'react-dom/client'; import App from './App'; const container = document.getElementById('root'); const root = createRoot(container); root.render(<App />);

Create-React-App migration to React version 18: Typescript

If you don’t use Typescript you can skip this portion.

First, let’s check out how many errors we have to deal with. This will vary from project to project depending on how many incompatible third-party libraries you may have but they’ll all be resolved in a similar fashion.

Run the following command:

Ouch, we got 36 errors to resolve. Luckily most of them are the same.

36 errors

I use Semantic UI in this project and there were several errors with the UI Radio component. For example, I had a setView function that took in the parameters from the onChange prop. For some reason, I lost the typing on the e and data parameters.

JavaScript
Parameter 'data' implicitly has an 'any' type. onChange={(e, data) => setView(data.value as number)}

I hit F12 (Windows users) or right-clicking and heading to the Type definition. On the prop of onChange to check out what it should be returning and manually set the types to the function.

types

Make sure to import the type from the library and set the types inside the function itself.

TypeScript
import type { CheckboxProps } from 'semantic-ui-react'; <Radio // other props onChange={(e: React.FormEvent<HTMLInputElement>, data: CheckboxProps) => { // whatever your function does } } />

Create-React-App migration to React version 18: Sentry

I also use the Sentry library to track errors in my project. Here’s a quick write-up on how that works. For sentry, I got some errors with the ErrorBoundary component. This will probably be patched up but we can do it ahead of time until then.

React version 18 requires children to be explicitly declared in the props, hence the error:

Bash/Shell
error TS2769: No overload matches this call. Overload 1 of 2, '(props: ErrorBoundaryProps | Readonly<ErrorBoundaryProps>): ErrorBoundary', gave the following error.

Thankfully, there’s a library called patch-package that allows us to fix this up. Let’s install it.

Bash/Shell
yarn add patch-package --dev

As before let’s check out the type definitions for the ErrorBoundary by stepping into it. Hitting F12 or right-clicking and going to the Type definition.

type definition

As suspected the type does not have the children prop. Let’s add it by setting it to a React.ReactNode.

TypeScript
export declare type ErrorBoundaryProps = { children: React.ReactNode; //...rest of the type, just ignore it

In order for patch-package to recognize this change we should run the following command in our terminal:

Bash/Shell
npx patch-package @sentry/react

This will create a file in our project indicating the changes we patched in the library.

JSON
diff --git a/node_modules/@sentry/react/types/errorboundary.d.ts b/node_modules/@sentry/react/types/errorboundary.d.ts index 4e1f326..779e0e7 100644 --- a/node_modules/@sentry/react/types/errorboundary.d.ts +++ b/node_modules/@sentry/react/types/errorboundary.d.ts @@ -9,6 +9,7 @@ export declare type FallbackRender = (errorData: { resetError(): void; }) => React.ReactElement; export declare type ErrorBoundaryProps = { + children: React.ReactNode; / **If a Sentry report dialog should be rendered on error */ showDialog?: boolean; /**

The final step is to add the following line to our scripts in our package.json.

JSON
"scripts": { // ...other scripts "postinstall": "patch-package" }

Sidenote

As a small aside if there are any libraries you don’t want to patch and just want to ignore the errors for the time being while the maintainers fix them up. (Or alternatively, you can open up a PR to fix it! 😬) Just add some ts-ignore to the file right before the error:

Wrapping it up

Create-React-App is still the most widely used method to bootstrap React apps so being able to migrate it is pretty important for some users. 🚀

If you liked this check out other posts like this at Relatable Code

If you liked this feel free to connect with me on LinkedIn or Twitter

Check out my free developer roadmap and weekly tech industry news in my newsletter.

If you see any typos or errors you can edit the article directly on GitHub

Hi, I'm Diego Ballesteros 👋.

Stay on top of the tech industry and grow as a developerwith a curated selection of articles and news alongside personal advice, observations, and insight. 🚀

No spam 🙅‍♂️. Unsubscribe whenever.

Envelope
Subscribe

You may also like these articles: