React 18 — What’s New, What Changed & Upgrade Guide
React version 18 was released. And since it is a major new version of React, it does, as you would expect, introduce some new, exciting features. Thankfully though, it does not break your existing code. What you learned about react still applies. The code you write still is the same. Updating indeed is a piece of cake.
All you have to do is run npm install and install the latest versions of React and React DOM. And then there’s one single change you have to make to your codebase to take advantage of all the new features unlocked and added by React 18.
npm install react@18 react-dom@18
You have to go to your route entry file, typically index js. And then in that file, replace the import of React DOM from React DOM with this import where you import from React DOM slash client. So that’s a tiny addition you have to make to this import statement. And replace the line where you call React DOM render to render the root component into some element in the index HTML file with the line below, where you call create root on React DOM instead and you pass the root element in the index HTML file to create root. And then on this root object, which is returned by create root, you call render to render the root component into this root element in index HTML.
That’s the only change you have to make to your code. No other code changes are required. That’s only in one file and only in these two lines of that file, as you see it’s super simple and all the rest you learned still applies. There’s nothing else you have to change. Now, why was this change made? Why was this syntax changed? Because by changing to it, you opt in to a new set of features and into a lot of behind-the-scenes improvements and changes that were introduced by React 18.
The most important new feature introduced by React 18 is a feature called concurrency, and that’s actually rather a concept that is made up of a set of features that were unlocked and added by React 18. Concurrency is all about processing multiple simultaneous state updates. Consider a list that updates as a user types into an input field. If there is a lot of data to be processed or the logic for processing the user input is rather complex, the user interface can get sluggish and slow especially on slower devices.
In the past, prior to React version 18, React always processed all state updates in the order in which they were triggered. And the next state update could only be processed once the previous one was done. With React 18 and the addition of the concurrency concept, you can tell React that a certain state update has a lower priority than another state update. And React is then able to treat the other updates with higher priority.
Now, you tell React about a state update that has a lower priority by using one of the new APIs introduced with React 18.
You can use the useTransition hook or the startTransition function in places where hooks can’t be used. For example, in class-based components to tell React that a certain state update process is about to start and that it shouldn’t wait for this process to finish before processing other state updates. So the rap state update will have a lower priority. In other cases, you might have a value that’s generated by some state update that you maybe don’t directly control, and you can use useDeferredValue to let React know that an older version of the value should be shown until the new value is ready instead of waiting with the entire component and UI update until the new value is available.
Now, these functions and hooks are obviously, very new and therefore we will, of course, have to see which patterns and best practices will emerge based on them. You should definitely not start wrapping all your or state updating calls or all your values with those functions and hooks. Instead, you should use them in niche cases were very complex calculations are going on where the interface is sluggish and you have no other way of improving it, or you have no other obvious error that could be causing this behaviour, then these functions and hooks can be helpful.
As an application developer, you will probably never work with these hooks. Now, besides these new APIs and hooks, you also get some changes for existing features. For example, state batching.
State batching already existed in older versions of React as well and it’s all about grouping multiple state updating calls together so that they are executed as one state update call instead of multiple calls. This ensures that the component to which the state updates belong is not evaluated and executed multiple times unnecessarily, but that at it in status only executed once.
Now, the problem is that with React 17 or older, this feature already existed, but it only worked inside of synchronous React event handler functions. If you, for example, had a function that was triggered because a timer expired, state updates performed in that function were not batched together. This changed with React 18 and state batching now always works no matter where you make your state updates. Now, one note about this state batching example, if you try to reproduce this on your own with React 18, you might still see double log outputs for state changes that should be batched together. And that is related to strict mode, which during development, and only there, renders a component twice to perform some extra checks.
This able strict mode by removing it from index JS, if you have it there, and then thereafter, you’ll see the updated state batch and behaviour.
Another important change affects the suspense component. The suspense component was also already added in older versions of React, and it can be used to be wrapped around lazily loaded components. Lazy loading simply means that you implement code splitting to only load to code for a certain component when it is needed. This can help with performance since less code has to be downloaded initially. This is often used in combination with routing.
Now you could already use the suspense component to show a fallback component, for example, a loading spinner until the code for the lazily loaded component was downloaded. However, prior to React version 18, you could not use the suspense component if you also used server site rendering. Now, of course, many apps might not use that but if you did use it, you were not able to use the suspense component because it would cause an error. With React 18 that changed and you can now use this component as you always were able to use it on the client-side, on the server-side as well.
As a side note, we will probably see more exciting changes to the suspense component in the future now that React 18 is out because the React team does plan to also make the suspense component work with data fetching not just with code fetching for lazily loaded components. The idea is that your components if they’re fetching data, can tell React that they are and tell React when they are done fetching data. And then the suspense component, which is somewhere above the data fetching components in the component tree is able to show a fallback for the components that are fetching data until the data is there. This means that you won’t have to manage the loading state manually inside of your components anymore and you can decouple the logic for doing that from your user interface.
Now, this feature is not there yet, but it’s planned to be added in the future and React 18 also lays the foundation for that.
Another exciting feature, which isn’t there yet but which we’ll probably see in the future now that React 18 was released, is server components. These are components that are not just pre-rendered on the server, as you can already do today with server-side rendering. But instead, these are components that are meant to only execute on the server and yet work seamlessly together with client site components.
Once this feature is added to React, it will effectively turn React into kind of a full-stack framework or library which allows you to make server site with client site code so that you’re not just limited to building user interfaces but you instead can also perform certain server site only logic in your React app.
This could be used for performing tasks on the server that should not run on the client for security or performance reasons.
This feature is not there yet. You can’t yet use these components. It’s an alpha stage only and will probably change a lot over the next months. But we will probably see it in the future