Believemy logo purple

Les nouveautés de React 19

React 19 vient tout juste d'être annoncé par l'équipe de Meta. De puissantes nouveautés ont fait leurs apparitions presque deux ans après la sortie de React 18.3. Découvrons toutes les nouveautés avec React 19.
Mis à jour le 3 décembre 2024
Believemy logo

Sommaire

1. La nouvelle fonction use 💫

    1.1 Exemple 1 : Avec une promesse

    1.2 Exemple 2 : Avec un contexte

2. Les nouveautés pour les refs 👀

3. Le nouveau hook useOptimistic()

4. Le support des balises meta 👑

5. Les Clients Components et les Servers Components

    5.1 Les Clients Components

    5.2 Les Servers Components

        5.2.1 Utiliser un Server Component

        5.2.2 Exemple

6. Les Servers Actions 📝

    6.1 Sans les Servers Actions

    6.2 Avec les Servers Actions

7. Les nouveaux hooks useFormStatus() et useActionState() 🔗

    7.1 Comment utiliser useFormStatus() ?

    7.2 Comment utiliser useActionState() ?

8. Le nouveau compilateur 🤖

9. Conclusion

 

La nouvelle fonction use

Il s'agit d'un tout nouveau React Hook un peu particulier puisque ce dernier peut être appelé de manière conditionnelle sans lancer une erreur. Elle permet de lire la valeur d'un Context ou d'une Promesse.

JSX
const value = use(ressources);

 

Exemple 1 : Avec une promesse

Dans le cas où nous souhaiterions utiliser la fonction use avec une promesse, nous devrions utiliser Suspense le temps que la requête soit résolue ou rejetée. Voici ce que nous aurions pour une promesse qui récupère un message :

JSX
import { use } from 'react';

const Message = ({ promiseForMessage }) => {
    const message = use(promiseForMessage);

    return (
        <div className="message">
            {message.text}
        </div>
    )
}

Et pour notre promesse :

JSX
import { Suspense } from 'react'
import Message from './Message'

function App() {
  const promiseForMessage = fetch('https://jsonplaceholder.typicode.com/message').then((res) => res.json());

  return (
    <Suspense fallback={<div>Loading</div>}>
      <Message promiseForMessage={promiseForMessage} />;
    </Suspense>
  )
}

export default App

 

Exemple 2 : Avec un contexte

Il est également possible d'utiliser la fonction use avec un contexte grâce à createContext. Voici par exemple ce qu'un mélange de ces deux fonctions donnerait : il suffirait uniquement de passer notre contexte à la fonction use.

JSX
import { createContext, use } from 'react'

const IngredientsContext = createContext();

function Ingredients() {
    const ingredients = use(IngredientsContext);

    return (
        <ul>
            {ingredients.map((ingredient) => {
                return <li key={ingredient}>{ingredient}</li>
            })}
        </ul>
    )
}

export default function App() {
    return (
        <IngredientsContext value={['Chocolat', 'Kiwi', 'Flocons']}>
            <Ingredients />
        </IngredientsContext>
    )
}

D'ailleurs, une petite nouveauté de React 19 a été utilisée dans ce petit exemple : nous n'avons pas eu besoin d'utiliser IngredientsContext.Provider. Il suffit uniquement d'utiliser notre contexte avec son nom IngredientsContext.

 

Les nouveautés pour les refs

React 19 apporte également des nouveautés pour les refs.

En pratique, les refs sont dorénavant transmises comme étant des props plutôt que de devoir utiliser le React Hook forwardRef.

Avant React 19, nous devions utiliser les refs de cette façon si l'on souhaitait transmettre une ref à un composant :

JSX
import { forwardRef } from "react";

const button = forwardRef(props, ref) => (
	<button ref={ref}>
		{props.children}
	</button>
));

Désormais voici comment il est possible d'utiliser les refs :

JSX
const button = ({ ref, children }) => (
	<button ref={ref}>
		{children}
	</button>
));

 

Le nouveau hook useOptimistic ()

Le Hook useOptimistic nous propose de mettre à jour l'interface avant que les données ne soient changées sur le serveur, afin de réduire l'attente et d'augmenter la fluidité des requêtes.

Par exemple, quand l'utilisateur poste un nouveau message.

Pour ce faire, il faut créer un élément avec useOptimistic qui prend en paramètre la valeur actuelle et retourne un objet qui contient :

  • optimisticValue - la valeur anticipée
  • updateOptimistic - la fonction qui permet de changer la valeur
JSX
import { useOptimistic, useState } from 'react';

const Messages = () => {
    const [messages, setMessages] = useState([
        {
            id: 4,
            content: "Hey",
            pending: false
        }
    ]);

    const [optimisticMessages, newOptimisticMessage] = useOptimistic(
        messages,
        (state, newMessage) = [
            ...state,
            {
                id: `newMessage-${messages.length}`,
                content: newMessage,
                pending: true
            },
        ],
    );

    return (
        <>
            <div>
                {optimisticMessages.map(message => (
                    <div
                        key={message.id}
                        style={{ background: message.pending ? "gray" : "transparent" }}
                     >
                        {message.content}
                    </div>
                ))}
            </div>

            <form action={async (data) => {
                const newMessage = data.get('content');
                newOptimisticMessage(newMessage);
                await sendNewMessageForBackend(newMessage);
            }}>
                <input type="text" name="content" placeholder="Votre nouveau message" />
                <button type="submit">Ajouter mon message</button>
            </form>
        </>
    )
}

    

Maintenant, quand l'utilisateur veut ajouter un message, l'interface est mise à jour de manière optimiste (avant que le changement ne soit fait dans la base de données sur le serveur).

Tant que le message est en train de s'envoyer, on modifie le style en changeant la couleur du fond en gris clair (avec message.pending ? "gray" : "transparent" sur notre exemple).

Une fois que notre message est envoyé avec notre fonction sendNewMessageForBackend, on peut imaginer qu'on modifie le state de messages ce qui modifie aussi le state contrôlé avec notre Hook useOptimisticValue, ce qui passe le message avec un fond transparent pour montrer qu'il a bien été ajouté.

Astuce

Nous aurions pu également ne pas montrer à l'utilisateur que son message est en train d'être ajouté si nous n'avions pas modifié la couleur du background du message. Dans ce cas, l'utilisateur aurait eu l'impression que son message aurait été ajouté en un clic.

 

Le support des balises meta

Cette nouvelle version 19 de React propose désormais l'accès à certaines balises meta comme :

Voici par exemple ce qu'il est possible de faire dans le but de personnaliser les balises meta avec React 19 :

JSX
const MainPage = () => {
    return (
        <>
            <title>Believemy</title>
            <meta name="description" content="Formations pour devenir développeur web" />
        </>
    );
}

 

Les Clients Components et les Servers Components

Déjà présents sur le framework NextJS, ils arrivent enfin officiellement sur React 19 !

Il s'agit d'un concept assez simple à comprendre : par le passé, tous les composants étaient chargés par le client donc par l'utilisateur d'un site. Ceci se traduisait jusque-là par des temps de chargement assez longs pour ce dernier, ce qui évidemment, réduisait les performances et donc le référencement dans les moteurs de recherche (pour qui la vitesse est une métrique importante des Web Core Vitals).

 

Les Clients Components

C'est le type de composants utilisé par tous les composants d'un projet React jusqu'à la version 18.3. Voici comment ils fonctionnent.

Exemple de fonctionnement d'un client component
Exemple de fonctionnement pour un Client Component

Dans les Clients Components, l'utilisateur charge lui-même le bundle (l'ensemble des dépendances qui sont utilisées pour charger une page).

Comme on peut le voir, le serveur ne fait qu'envoyer les ressources à l'utilisateur. C'est l'utilisateur qui charge et utilise les ressources de son périphérique pour afficher la page finale.

Les problèmes des Clients Composants sont assez nombreux :

  1.  Les temps de chargement d'une page dépendent de la connexion utilisée par l'utilisateur mais aussi de son périphérique
  2.  Les délais allongés réduisent les signaux pour les Web Core Vitals et ainsi le référencement de la page.
  3. L'expérience passée à attendre qu'un site se charge dégrade l'envie et le plaisir de l'utilisateur.

Heureusement, une solution a été trouvée : l'arrivée des Servers Components.

 

Les servers components

C'est le nouveau type de composants qui est utilisé avec React 19. Analysons le fonctionnement des Servers Components avec cette illustration :

Exemple de fonctionnement d'un client component
Exemple de fonctionnement pour un Server Component

Dans les Servers Components, le serveur charge lui-même le bundle et l'envoi déjà prêt à l'affichage à l'utilisateur.

Comme on peut le voir, le client ne fait que réceptionner les ressources transmises avec le serveur. C'est le serveur qui charge et utilise ses ressources pour afficher la page finale.

Les Servers Components ont donc plusieurs avantages :

  1.  La puissance de calcul utilisée est celle du serveur, pas celle du périphérique du client, ce qui améliore les performances de chargement du site et donc le référencement dans les moteurs de recherche.
  2.  Les Servers Components ont un accès complet aux ressources back-end (donc au système de fichiers par exemple). Les données y sont sécurisées car elles ne passent par sur le client.
  3.  Le client reçoit une version minimale du bundle sans les dépendances qui ont permis de construire la page.

 

Utiliser un Server Component

Pour utiliser un Server Component, il faut utiliser la directive use server. Il s'agit d'une source d'erreur fréquente si vous connaissez Next.JS puisqu'avec ce dernier tous les composants sont des composants serveurs, à l'inverse de ReactJS dans lequel tous les composants sont des composants client par défaut.

Il y a cependant quelques limites pour les Servers Components :

  1.  Impossible d'utiliser les Hooks comme useState, useEffect.
  2.  Impossible d'accéder aux fonctionnalités qui sont intégrées sur le navigateur comme le local storage.
  3.  Certains Hooks Customisés ne peuvent pas être utilisés s'ils dépendent des fonctionnalités du navigateur (certaines dépendances ne fonctionnent donc pas dans un Server Component).

 

Exemple

Voici un exemple d'utilisation sur React 19 pour un Server Component.

JSX
'use server';

export default async function articles() {
    const res = await fetch("https://api.example.com.com/articles");
    
    const articles = res.json();

    return (
        <>
            {articles.map(article => <div key={article.id}>{article.title}</div>}
        </>
    )
};

Cet exemple se veut simple : on récupère sans utiliser un state avec useState par exemple les articles directement dans le composant.

C'est étrange au début, libérateur à la fin. 🥰

 

Les Servers Actions

Ici, on reprend les mêmes et on recommence : il s'agit d'une fonction qui sera exécutée sur le serveur dès qu'un formulaire sera envoyé.

 

Sans les Servers Actions

Nous étions obligés avant les Servers Actions de détecter l'envoi du formulaire et d'appeler ensuite une méthode qui irait récupérer les données renseignées, et qui effectuerait une requête du côté du client.

Ceci a le désavantage de ne pas être sécurisé car l'utilisateur peut voir le flux des requêtes ainsi que le contenu des méthodes.

Voici par exemple ce que nous avions sans les servers actions :

JSX
const register = async (e) => {
    // Etc
}

<form onSubmit={(e) => register(e)}>
    <input name="pseudo" placeholder="Pseudo" id="pseudo" />
    <input name="password" placeholder="Mot de passe" id="password" />
    <button type="submit">Créer mon compte</button>
</form>

 

Avec les Servers Actions

Avec React 19 il est désormais possible d'utiliser les Servers Actions. Ces derniers permettent comme nous l'avons vu d'exécuter une méthode sur le serveur et donc de sécuriser les appels API et les données.

Voici le même exemple avec les servers actions :

JSX
const register = async (data) => {
    'use server';
    const newUser = {
        pseudo: data.get('pseudo'),
        password: data.get('password')
    }

    await fetch("...");
}

<form action={register}>
    <input name="pseudo" placeholder="Pseudo" id="pseudo" />
    <input name="password" placeholder="Mot de passe" id="password" />
    <button type="submit">Créer mon compte</button>
</form>

Quelques petits choses à bien noter sur les Servers Actions :

  • L'attribut utilisé est action à la place de onSubmit
  • Il faut préciser use server dans la méthode qu'on appelle pour l'exécuter sur le serveur
  • Les données sont envoyées par React dans la méthode appelée

 

Les nouveaux hooks useFormStatus() et useActionState()

Pour utiliser les Servers Actions, React 19 propose deux nouveaux Hooks : useFormStatus et useActionState.

Chacun de ces Hooks nous permet de modifier notre code en fonction des actions utilisées.

Analysons chacun des deux.

 

Comment utiliser useFormStatus() ?

Ce tout nouveau Hook fonctionne avec les Server Actions de React 19. Il permet de connaître le status sur les formulaires, ainsi que les données envoyées et la méthode qui a été utilisée.

On peut utiliser ce nouveau Hook de cette manière :

JSX
const { pending, data, method, action } = useFormStatus();

Voici à quoi correspondent ces différents noms :

  • pending - Pour savoir l'état du formulaire et s'il est en cours d'envoi (true si oui, false si non)
  • data - Pour récupérer les données transmises sous forme d'un objet
  • method - Pour récupérer la méthode HTTP
  • action - Pour exécuter une fonction passée en référence

Il est aussi possible d'utiliser une version simplifiée avec le code suivant :

JSX
const { status } = useFormStatus();

Voici un exemple concret :

JSX
import { useFormStatus } from "react";

function SubmitButton() {
    const status = useFormStatus();
    return (
        <button disabled={status.pending}>
            {status.pending ? "Chargement..." : "Envoyer"}
        </button>
    )
}

const serverAction = async () => {
    "use server";
    await newPromise(resolve => setTimeout(resolve, 5000)); // On attend 5 secondes
}

export default const Form = () => {
    return (
        <form action={serverAction}>
            <SubmitButton />
        </form>
    );
};

Voici ce que fait notre petit exemple :

  • On crée un composant SubmitButton dont son texte change entre "Chargement..." et "Envoyer" selon le status de l'envoi de notre formulaire
  • On crée une fausse attente de 5 secondes dans serverAction pour que la requête dure 5 secondes afin qu'on puisse voir le résultat de useFormStatus()
  • On sait quand notre formulaire est toujours en train d'être envoyé grâce à status.pending

Le Hook useFormStatus est ainsi vraiment très intéressant pour modifier l'interface selon l'envoi d'un formulaire par exemple.

 

Comment utiliser useActionState() ?

L'intérêt ici du Hook useActionState est très intuitif : permettre une modification du state en fonction de la réussite ou de l'échec d'une action.

Si tout se passe bien ? On met à jour les données du state.

Sinon ? On affiche un message pour dire que nous avons eu une erreur. On peut utiliser useActionState de cette manière avec React 19 :

JSX
const [state, formAction, isPending] = useActionState(action, 0);

Nous avons ici :

  • state - Représente le state initial au premier rendu et le state mis à jour par la fonction action passée en paramètre (vous comprendrez mieux dans l'exemple)
  • formAction - Une nouvelle action que l'on peut utiliser dans l'attribut formAction d'un bouton
  • isPending - Pour détecter quand une action est en train d'être réalisée ou non (et donc pour changer l'interface ensuite)

Enfin, nous passons dans useActionState :

  • action - la méthode que nous voulons utiliser quand le formulaire est envoyé
  • 0 - notre state initial

En voici un exemple.

JSX
import { useActionStatus } from "react";

async function add(prevState, data) {
    return prevState + 1;
}

export default function Form() {
    const [state, formAction, isPending] = useActionsState(add, 0);

    return (
        <form>
            {state}
            <button formAction={formAction}>Ajouter</button>
        </form>
    )
}

 

Le nouveau compilateur

Il s'agit de la plus grande annonce sur la version 19 de React JS : jusqu'à la version précédente, les développeurs utilisaient des techniques afin d'optimiser leur code, grâce à des fonctions dédiées :

Ceci est désormais de l'histoire ancienne avec React 19 ! 🥳

Le tout nouveau compilateur de React détecte désormais notre code et l'optimise tout seul de manière intelligente. Ceci permet d'avoir des performances décuplées pour l'expérience utilisateur de l'optimisation pour les moteurs de recherche.

 

Conclusion ✨

Voici tout ce qu'il fallait savoir sur les nouvelles fonctionnalités de React 19 ! Cette version apporte beaucoup de nouveautés et des optimisations pour les performances.

De nos jours, il s'agit sans contestation possible de la meilleure librairie front-end pour créer des sites internet.

Si vous voulez allez plus loin et apprendre les dernières nouveautés de React, jetez donc un oeil sur notre formation dédiée à React. Nous la mettrons à jour avec la version 19 dès que React sortira officiellement cette nouvelle version pour un usage en production.

Formation React
Page d'accueil de notre cours sur React

 

Catégorie : Développement
Believemy logo
Commentaires (0)

Vous devez être connecté pour commenter cet article : se connecter ou s'inscrire.

Essayez gratuitement

Que vous essayiez de scaler votre start-up, de créer votre premier site internet ou de vous reconvertir en tant que développeur, Believemy est votre nouvelle maison. Rejoignez-nous, évoluez et construisons ensemble votre projet.

Believemy is with anyone