React 19 has been officially announced!

Discover exciting new features that can revolutionize your app development process.

2024-04-24

#Frontend

Overview

Since the release of React 18, almost 2 years have passed. Version 18 was available for download at the end of March 2022, and for many developers, it was a breakthrough version, mainly due to the significant performance improvements compared to previous versions of the library. That was when we got Concurrent Rendering Mode in React, which enabled concurrent rendering. Why is this worth mentioning? Because in this mode, we gained options for pausing, suspending, and resuming, as well as completely abandoning rendering, which was a breakthrough moment. With the help of concurrency mechanisms such as useDeferredValue, startTransition, or Suspense, we could defer the update of parts of the user interface, update the state without blocking the user interface, and display an optional component while waiting for data retrieval.

Before we get to the main part of the article, it is worth mentioning that React Conf 2024 will take place soon, on May 15-16 in Henderson, Nevada, and will be available online. The official React website also states that the next library update (currently 18.2.0) will be a major version, namely React 19. We do not yet know the official release date, but in this article, we will try to explore the innovations that await us in the announced version.

React compiler

The basic idea of React is that developers define the user interface as a function based on the current state. When the state changes, React re-renders the component. However, there are situations where React is too reactive and renders the component too many times. An example could be creating a new array or object in each component render. Even though the array or object may have the same values, React will re-render the view. To deal with such situations, developers used useMemo and useCallback.

Although this solution served its purpose, it cluttered the code, making it easier to make mistakes. Maintaining such code required additional effort from the programmer.

The React team worked on a solution and decided that the answer to this problem should be a compiler that automatically renders user interface components precisely based on state changes. As a result, developers won't have to remember to use useMemo and useCallback because React will intelligently render only the necessary parts of the user component when necessary.

The React Compiler should be able to safely compile code for performance based on knowledge of JavaScript and React rules. We know that React components must be idempotent - return the same value for the same input - and cannot change properties or state values. This is intended to improve the quality of rendering, which translates into the speed of the application.

Not so long ago, the mentioned compiler was only a research project, but it is now used in the production version of Instagram. The React team mentioned that work is underway to prepare the first open-source version and to extend the compiler to other Meta products.

Actions

Actions are a new way to deal with forms. An action is a function that can be both synchronous and asynchronous, so it can be defined on the client side using JavaScript or on the server using the 'use server' directive. React provides two hooks: useFormState, which will be used to update the state after the form action result, and useFormStatus, which will provide information about the status of the last form submission.

An example use of action:

1
2
3
4
<form action={search}>
  <input name="query" />
  <button type="submit">Search</button>
</form>

By default, actions are sent within a transition – this means that the page where the form is located is interactive during action processing. As mentioned above, actions support asynchronous functions, so we can use async/await in them. Additionally, developers can display a pending interface when an asynchronous request begins, such as data retrieval. This is done using the isPending state.

In this context, it is worth mentioning useOptimistic. This is a hook that allows showing a different state when an asynchronous action is in progress.

Below is the code from the documentation:

1
2
3
4
5
6
7
8
9
10
11
12
import { useOptimistic } from 'react';

function AppContainer() {
  const [optimisticState, addOptimistic] = useOptimistic(
    state,
    // updateFn
    (currentState, optimisticValue) => {
      // merge and return new state
      // with optimistic value
    }
  );
}

To better visualize the useOptimistic function, let's use an example. Imagine that we are traveling by train and we have a weak internet connection. We are browsing our shopping cart on a website and have decided that we would like to change the quantity of one of the items being purchased. By clicking on the plus icon, the quantity of the given product in the cart will first increase, and then the cart value will be updated (so the user will get the effect they would have with faster internet and faster action processing). When the asynchronous action is executed, we then update the cart state and the quantity of products with data from the server. In the event of a successful action, the overall cart value and the number of products will not change, whereas in case of an error, the mentioned information will be reverted to the previous state (before clicking on the icon increasing the quantity of products in the cart).

Directives

In this section, we will present new directives that will be added as a result of the React library update.

'use client' – a directive that indicates that the interface will be interactive. In this case, instead of HTML code, the server returns JavaScript code. The code returned by the server contains information about how the HTML code should be generated by the browser. What does an interactive interface mean? It means that we allow the component to change its state, and the user can trigger an action (onClick, onChange) when, for example, clicking on a component element. However, this negatively affects the bundle size, so the browser will need more time to load the page or application. The directive is added at the beginning of the file, above the imports. It is also worth noting that all components used in the file with this directive are treated as part of the client package, even those server-side components mentioned below.

Good examples describing the use of the above directive are:

  • filter buttons
  • product add-to-cart buttons with counters
  • cart price update
  • various animations

'use server' - a directive indicating that the code will be rendered on the server side. Unlike client components, server components do not affect the size of the bundle downloaded by the browser, which means they do not slow down the application. Server components are perfect for non-interactive components. Their advantage is that they can be asynchronous functions, so we can - within the component - directly connect to the database and retrieve data from it. Another advantage of server components is security, since sensitive data and logic can be kept on the server side. If we don't need interactive components with states on the server side, we can generate the entire HTML code of the page, allowing for a quick preview of the content.

Good examples describing the use of the above directive are static elements on the page such as:

  • navigation
  • sidebar
  • footer with links
  • product pages

The latter can be generated together with the image and details on the server side and returned to the user.

Document metadata

By metadata, we mean, among other things:

  • page title
  • page description
  • keywords
  • author
  • copyright

These are pieces of information contained in the <title> and <meta> tags of our page.

There are pages and applications where one metadata is sufficient, e.g. a company information page. In a case of a store we need different metadata; for each product, metadata can - and even should - be different. HTML tags for metadata must be placed in the <head> document, which is usually rendered in the component in the main directory of the application. In such cases, there was a problem of how to change them. One technique to solve this problem was to render a special component that moves the <title> <meta> tags to <head>. In the new version of React, we will be able to edit <title>, <meta>, <link> from anywhere in the component tree. Additionally, this method has been unified, and it will work identically in client, server, and Server Side Rendering components.

Asset loading and data fetching

From the latest information, it follows that React 19 will provide faster image and other files loading. When a user browses the current page, React will load images and scripts in the background, resulting in shorter waiting times when switching to another page.

By default, browsers load style sheets, images, and fonts independently, which can lead to jumping user interface elements when individual resources are being retrieved. At this point, it is worth mentioning Suspense again, which allows specifying what should be displayed as a fallback when data from the API or component code are still being loaded. In React 19, Suspense has been integrated with the resource loading cycle (style sheets, images, fonts) in such a way that React takes them into account to determine whether the content is ready to display the component. This is intended to solve the problem mentioned above.

New API interfaces have been introduced as well. Here, we mention preload and preinit, which increase control over resource loading.

Other changes

Finally, we would like to mention changes compared to the previous version of the React library:

  • forwardRef
- will become a regular property named ref, which can be passed down through component hierarchies.
  • use(Promise)
- the component calling use is suspended while the promise passed to use awaits resolution. If the component calling use is "wrapped" in Suspense, a fallback will be displayed until the Promise is resolved.
  • use(Context)
- replaces useContext. It works the same as the mentioned hook, but additionally, it can be called in conditional functions and loops. This is a big step towards optimization because it will be possible to conditionally skip component rendering even if the context has changed.
  • <Context.Provider>
- will be replaced by <Context>, which is intended to be more intuitive to use. It is used to "wrap" components using context.

Summary

There is no doubt that the React library is evolving. With each new release, the React team helps developers significantly in their work. Moreover, it improves the overall experiences of users who use applications created using this library. The mechanisms proposed by React developers show the direction of development chosen by the creators. We see a lot of emphasis on optimization and application rendering speed.

Functionalities that we could use in previous versions of React are being developed and moving into stable mode. Additionally, new hooks give developers new possibilities when creating applications. The React team also tries to provide ready-made solutions to problems, such as those described in the Document metadata or Asset loading and Data fetching sections.

Although we received information about what to expect in the new version of the React library, we still need to be patient and wait for the official version, which may be released later this year.

Share this post

Related posts

Frontend

2024-04-04

Next.js 14: Exploring fundamental concepts

Frontend

2023-09-20

Website Accessibility

Want to light up your ideas with us?

Józefitów 8, 30-039 Cracow, Poland

hidevanddeliver.com

(+48) 789 188 353

NIP: 9452214307

REGON: 368739409