

React is a popular front-end library that allows developers to build powerful and scalable user interfaces. With the release of React version 18, there are many new features and improvements that can enhance the developer experience and improve the performance of React applications. In this post, we’ll cover the steps needed to upgrade a React application from version 17 to version 18. The React team recently released React 18 with improvements like automatic batching, a new suspense feature, and new APIs like startTransition.
React 18 is stable and ready to use. In most cases the upgrade process should be quick and easy, requiring only an npm/yarn update and a switch to the new root API. You should still test all your components as they may behave differently in some situations, such as in Strict Mode or when automatic batching applies.
Before looking at the improvements/features made in React 18, let’s have a look at the issues with React 17.
Issues with React 17
The React community has noticed some issues or problems with the library which require improvement. **React 18 and higher versions wouldn’t need to be released if React 17 was functioning flawlessly.
- Render throws an error if undefined is returned: When a component returns a value of undefined, the application will break.
- Set State of unmounted component gives a warning: In an attempt to update the state of an unmounted component, React might warn you of a memory leak.
- Strict mode console log suppression: From community feedback, it was noticed that the suppression of the console log message when using Strict Mode creates confusion since only one shows instead of two.
- Memory consumption: React 17 and earlier had issues with memory leaks, especially in unmounted components.
Highlights of React 18
- Automatic batching of state updates: In React 18, state updates will be automatically batched by default. This means that multiple state updates that occur within a single render cycle will be batched together, resulting in better performance and fewer unnecessary renders.
- New suspense features: React 18 will introduce new suspense features that will make it easier to handle asynchronous operations such as data fetching and code splitting.
- Improved server-side rendering: React 18 will include improvements to server-side rendering that will make it easier to build server-rendered React applications.
This article will briefly describe the step-by-step process of upgrading to React 18.
Side Effects
- Core changes
- Router Upgrade
- Redux Upgrade
- Strict Mode
Core changes
How to Upgrade to React 18?
You can install the latest version of React 18 and React DOM with either npm/yarn like this below:
npm install react react-dom
or, if you’re using yarn:
yarn add react react-dom
ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it’s running React 17.
In React 18, the Root API provides a more intuitive way to manage roots. It enables the new concurrent renderer, so you can opt into using concurrent features. After that, you’ll want to use createRooot instead of render. To do that, update ReactDom.render to ReactDom.createRoot to create a root, and render your app using root
The changes to be made in src/app/index.tsx.
In v17:
import { render } from 'react-dom'; const container = document.getElementById('app'); render(<App tab="home" />, container);
In v18:
import { createRoot } from 'react-dom/client'; const container = document.getElementById('app'); const root = createRoot(container); // createRoot(container!) if you use TypeScript root.render(<App tab="home" />);
Updates to Typescript
- VFC is deprecated hence, change it to FC.
- Explicit type definition for children.
- useCallback params to be strictly typed.
You can check the React 18 typings pull request for a complete list of type-related changes.
Router upgrade:
The current size of the new package is roughly 6kB. According to a tweet by Michael Jackson, the co-creator of React Router, they were able to achieve this by dropping support for any features earlier than IE11. With a smaller bundle size, your app has a smaller memory footprint and is faster than before. React 18 won’t support React router V5. Hence we need to upgrade it to V6. Upgrading the React router from V5 to V6 involves many breaking changes.
In this section, we will see the newest features in react router
Below are some of the changes in router:
- Convert <Switch> elements to <Routes>
- Remove <Redirect> inside <Switch>
- Use useNavigate instead of useHistory
- Remove ActiveClassName and ActiveStyle from <NavLink>
- Replace useRouteMatch with useMatch()
- Remove Exact keyword inside Route
- render method is not supported inside Route. Instead use element
- Cannot use RouteComponentProps type.
Installing React Router v6
To upgrade to React Router v6, you’ll first need to uninstall v5 and install v6:
yarn add react-router-dom@next
Note that the package name has changed from react-router-dom to react-router-dom@next.
Changes in Route Configuration
One of the major changes in React Router v6 is the way routes are configured. In v5, we typically used the <Route> component to define routes, like this:
import { Route } from 'react-router-dom'; <Route path="/about" component={About} />
In v6, the Route component has been replaced with the Routes component. Instead of defining individual routes with <Route>, we define all of our routes using <Routes>:
import { Routes, Route } from 'react-router-dom'; <Routes> <Route path="/about" element={<About />} /> </Routes>
Note: we now use the element prop to specify the component that should be rendered for a particular route.
Changes in Link and NavLink Components
In React Router v6, the Link and NavLink components have also been updated. In v5, we typically used these components like this:
import { Link, NavLink } from 'react-router-dom'; <Link to="/about">About</Link> <NavLink to="/about" activeClassName="active">About</NavLink>
In v6, the Link component has been replaced with the Link function, and the NavLink component has been replaced with the NavLink function:
import { Link, NavLink } from 'react-router-dom'; <Link to="/about">About</Link> <NavLink to="/about" style={({ isActive }) => ({ color: isActive ? 'greenyellow' : 'white' })}> About </NavLink>
Changes in Route Parameters
In React Router v5, we typically used the params prop to access route parameters. For example, if we had a route like this:
<Route path="/users/:id" component={User} />
We could access the id parameter in the User component like this:
function User(props) { const id = props.match.params.id; // ... }
In v6, route parameters are accessed using the useParams hook:
import { useParams } from 'react-router-dom'; function User() { const { id } = useParams(); // ... }
New Features in React Router v6
In addition to the changes described above, React Router v6 also introduces several new features:
- Routes as Components: In v6, we can define routes as components, which makes it easier to compose routes and share route configuration.
- Routes with Multiple Paths: In v6, we can define multiple paths for a single route, which makes it easier to handle complex route patterns.
- Relative Links: In v6, we can use relative links to navigate to other pages within the same route hierarchy.
- New location context: The new location context API allows you to access the current location and navigate programmatically from anywhere in your application, without the need for withRouter.
- No more exact prop: In v6, you don’t need to use the exact prop anymore to match routes exactly. Instead, the default behavior is to match routes exactly.
Please find the link for the usage of most used hooks.
React Router v6: The future of Reach Router and React Router – LogRocket Blog
Benefits of React Router v6 over v5
The size of React Router v6 has been reduced significantly compared to previous versions. The difference between v5 and v6 is around 60 percent. Compiling and deploying apps will be easier and faster as a result of the size reduction.
React Router v6 allows routes to accept components as elements when constructing routes, and pass custom props to components. We may also nest routes and use relative links as well. This helps us prevent or reduce the definition of new routes inside various component files, and it also makes it easy to pass global data to components and props.
When redirecting instead of using useHistory, the new approach using useNavigate has been designed to fix the issue of redundant URL. It allows us to set the new route manually (navigate(“/home”)) instead of updating stale routes (history.push(“/home”)), which might be a bit ambiguous.
Finally, NavLink allows us to condition active links, which makes our code neater and simpler. Instead of passing two separate props for an active and inactive state, we can easily use a ternary operator to condition which style will be affected when a link is active or not.
Redux Upgrade:
Note: This is a minor upgrade, it is not mandatory that we need to upgrade Redux.
For managing the state, we started using Redux but after the introduction of Context api, we stopped using redux state management for new features. Still some of the old code uses Redux. In such cases, we have to upgrade Redux packages.
React 18 in Strict Mode:
Strict mode in react 18 is more constraining. Strict Mode currently helps with:
- Identifying components with unsafe lifecycles.
- Warning about legacy string ref API usage.
- Warning about deprecated findDOMNode usage.
- Detecting unexpected side effects.
- Detecting legacy context API.
- Ensuring reusable state.
Hence it’s not recommended to remove React.StrictMode in any case.
Stop Using Removed and Unsupported Features
Once all the above aspects have been addressed, your app should be fully compatible with React 18. Although there are a few more API surface changes, these shouldn’t impact the majority of apps. Here are some to be aware of:
- unstable_changedBits has been removed – This unsupported API allowed opting out of context updates. It is no longer available.
- Internet Explorer is no longer supported – React has officially dropped compatibility with Internet Explorer ahead of the browser’s end of support in June. You should not upgrade to React 18 if you still require your app to run in IE.
- Using Suspense with an undefined fallback is now equivalent to null – Suspense boundaries with fallback={undefined} were previously skipped, allowing code to cascade to the next parent boundary in the tree. React 18 now respects Suspense components without a fallback.
Conclusion
Upgrading from React version 17 to version 18 can be a straight forward process if you follow the given steps. By upgrading to React version 18, you can take advantage of new features and improvements that can enhance the developer experience and improve the performance of your React applications. As always, it is important to test your application thoroughly after any major upgrade to ensure that everything is working as expected.