Sommaire
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.2.1 Utiliser un Server Component
5.2.2 Exemple
6. Les Servers Actions 📝
7. Les nouveaux hooks useFormStatus() et useActionState() 🔗
7.1 Comment utiliser useFormStatus() ?
7.2 Comment utiliser useActionState() ?
9. Conclusion
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.
const value = use(ressources);
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 :
import { use } from 'react';
const Message = ({ promiseForMessage }) => {
const message = use(promiseForMessage);
return (
<div className="message">
{message.text}
</div>
)
}
Et pour notre promesse :
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
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
.
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
.
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 :
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 :
const button = ({ ref, children }) => (
<button ref={ref}>
{children}
</button>
));
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éeupdateOptimistic
- la fonction qui permet de changer la valeurimport { 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.
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 :
const MainPage = () => {
return (
<>
<title>Believemy</title>
<meta name="description" content="Formations pour devenir développeur web" />
</>
);
}
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).
C'est le type de composants utilisé par tous les composants d'un projet React jusqu'à la version 18.3. Voici comment ils fonctionnent.
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 :
Heureusement, une solution a été trouvée : l'arrivée des Servers Components.
C'est le nouveau type de composants qui est utilisé avec React 19. Analysons le fonctionnement des Servers Components avec cette illustration :
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 :
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 :
Voici un exemple d'utilisation sur React 19 pour un Server Component.
'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. 🥰
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é.
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 :
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 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 :
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 :
action
à la place de onSubmit
use server
dans la méthode qu'on appelle pour l'exécuter sur le serveur
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.
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 :
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 objetmethod
- Pour récupérer la méthode HTTPaction
- Pour exécuter une fonction passée en référenceIl est aussi possible d'utiliser une version simplifiée avec le code suivant :
const { status } = useFormStatus();
Voici un exemple concret :
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 :
SubmitButton
dont son texte change entre "Chargement..." et "Envoyer" selon le status de l'envoi de notre formulaireuseFormStatus()
status.pending
Le Hook useFormStatus
est ainsi vraiment très intéressant pour modifier l'interface selon l'envoi d'un formulaire par exemple.
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 :
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 boutonisPending
- 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 initialEn voici un exemple.
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>
)
}
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.
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.
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.