Retour au blog

React 20 Est Arrive: Server Actions Stable et Partial Prerendering Changent Tout

Salut HaWkers, React 20 est enfin la et ce n'est pas simplement une mise a jour incrementale. Cette version represente le plus grand changement architectural depuis les Hooks. Les Server Actions sont maintenant stables, le Partial Prerendering elimine l'ecran blanc, et le React Compiler fait de la memoisation automatique.

Si vous pensiez deja tout savoir sur React, preparez-vous a reapprendre certaines choses. Explorons tout ce qui a change.

Server Actions: La Star de React 20

Apres des mois en Canary, les Server Actions ont enfin gradue vers la version stable.

Que Sont les Server Actions

Les Server Actions permettent d'executer du code sur le serveur directement depuis des composants React, sans creer de routes API separees.

// Avant: Il fallait une route API + fetch cote client
// pages/api/submit.js
export default async function handler(req, res) {
  const data = JSON.parse(req.body);
  await saveToDatabase(data);
  res.json({ success: true });
}

// component.jsx
async function handleSubmit(formData) {
  const res = await fetch('/api/submit', {
    method: 'POST',
    body: JSON.stringify(formData)
  });
  return res.json();
}
// Apres: Server Action directement dans le composant
// actions.js
'use server'

export async function submitForm(formData) {
  const name = formData.get('name');
  const email = formData.get('email');

  await saveToDatabase({ name, email });

  return { success: true };
}

// component.jsx
import { submitForm } from './actions';

function ContactForm() {
  return (
    <form action={submitForm}>
      <input name="name" required />
      <input name="email" type="email" required />
      <button type="submit">Envoyer</button>
    </form>
  );
}

Avantages Pratiques

1. Moins de Boilerplate:

// Routes API eliminees
// Pas de fetch() manuel
// Pas de gestion manuelle des etats de chargement
// TypeScript de bout en bout

2. Progressive Enhancement:

// Le formulaire fonctionne meme sans JavaScript!
<form action={serverAction}>
  {/* Si JS echoue, le form soumet quand meme */}
</form>

3. Integration Avec useActionState:

'use client'
import { useActionState } from 'react';
import { submitForm } from './actions';

function Form() {
  const [state, formAction, isPending] = useActionState(
    submitForm,
    { message: '' }
  );

  return (
    <form action={formAction}>
      <input name="email" disabled={isPending} />
      <button disabled={isPending}>
        {isPending ? 'Envoi en cours...' : 'Envoyer'}
      </button>
      {state.message && <p>{state.message}</p>}
    </form>
  );
}

Partial Prerendering: Fin de l'Ecran Blanc

Le PPR (Partial Prerendering) resout l'un des problemes les plus anciens de React : le temps de chargement initial.

L'Ancien Probleme

L'utilisateur clique sur le lien

Ecran blanc (chargement du JS)

Ecran blanc (hydratation)

Le contenu apparait (enfin!)

Temps total: 2-5 secondes sur les connexions lentes

Comment Fonctionne le PPR

L'utilisateur clique sur le lien

Le contenu statique apparait IMMEDIATEMENT

Les parties dynamiques arrivent en streaming

Page entierement interactive

Temps pour le premier contenu: < 100ms

Implementation Pratique

// page.jsx - Partial Prerendering en action
import { Suspense } from 'react';

export default function ProductPage({ params }) {
  return (
    <main>
      {/* Partie statique - rendue au build */}
      <Header />
      <ProductDetails id={params.id} />

      {/* Partie dynamique - streaming */}
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews productId={params.id} />
      </Suspense>

      <Suspense fallback={<RecommendationsSkeleton />}>
        <Recommendations userId={getCurrentUser()} />
      </Suspense>

      {/* Statique a nouveau */}
      <Footer />
    </main>
  );
}

Metriques de Performance

Avant le PPR:

TTFB: 800ms
FCP: 2.1s
LCP: 3.2s
TTI: 4.5s

Apres le PPR:

TTFB: 50ms
FCP: 150ms
LCP: 800ms
TTI: 1.2s

Les entreprises qui ont adopte le PPR rapportent des ameliorations massives des Core Web Vitals.

React Compiler: Memoisation Automatique

Vous vous souvenez de toute cette complexite avec useMemo, useCallback et React.memo? Le React Compiler s'en occupe automatiquement.

Avant: Memoisation Manuelle

// L'enfer de la memoisation manuelle
const MemoizedList = React.memo(function List({ items, onItemClick }) {
  const sortedItems = useMemo(
    () => items.sort((a, b) => a.name.localeCompare(b.name)),
    [items]
  );

  const handleClick = useCallback(
    (id) => {
      onItemClick(id);
    },
    [onItemClick]
  );

  return (
    <ul>
      {sortedItems.map(item => (
        <ListItem
          key={item.id}
          item={item}
          onClick={handleClick}
        />
      ))}
    </ul>
  );
});

const ListItem = React.memo(function ListItem({ item, onClick }) {
  return (
    <li onClick={() => onClick(item.id)}>
      {item.name}
    </li>
  );
});

Apres: Code Propre

// Le React Compiler gere l'optimisation
function List({ items, onItemClick }) {
  const sortedItems = items.sort((a, b) =>
    a.name.localeCompare(b.name)
  );

  return (
    <ul>
      {sortedItems.map(item => (
        <ListItem
          key={item.id}
          item={item}
          onClick={() => onItemClick(item.id)}
        />
      ))}
    </ul>
  );
}

function ListItem({ item, onClick }) {
  return (
    <li onClick={onClick}>
      {item.name}
    </li>
  );
}

// Meme performance, code 60% plus court

Activer le Compiler

// babel.config.js
module.exports = {
  plugins: [
    ['babel-plugin-react-compiler', {
      // Options
    }]
  ]
};

// Ou dans Next.js 15+
// next.config.js
module.exports = {
  experimental: {
    reactCompiler: true
  }
};

Asset Loading API

Nouvelle API pour un controle precis du chargement des ressources.

Priorisation Intelligente

import { preload, prefetch, preinit } from 'react-dom';

function App() {
  // Preload critique - charge immediatement
  preload('/critical-image.jpg', { as: 'image' });

  // Prefetch - charge quand inactif
  prefetch('/next-page-data.json', { as: 'fetch' });

  // Preinit - initialise le script
  preinit('/analytics.js', { as: 'script' });

  return <MainContent />;
}

Chargement Conditionnel

function ProductGallery({ products }) {
  return (
    <div>
      {products.map((product, index) => {
        // 4 premieres images: priorite haute
        if (index < 4) {
          preload(product.image, {
            as: 'image',
            fetchPriority: 'high'
          });
        }

        return <ProductCard key={product.id} product={product} />;
      })}
    </div>
  );
}

Hooks Ameliores

React 20 apporte des ameliorations significatives aux hooks existants.

useDeferredValue Etendu

function SearchResults({ query }) {
  // Differencier les mises a jour non-urgentes
  const deferredQuery = useDeferredValue(query);
  const isStale = query !== deferredQuery;

  return (
    <div style={{ opacity: isStale ? 0.7 : 1 }}>
      <Results query={deferredQuery} />
    </div>
  );
}

useOptimistic Pour une UI Optimiste

function TodoList({ todos, addTodo }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, { ...newTodo, pending: true }]
  );

  async function handleAdd(formData) {
    const newTodo = { text: formData.get('text') };

    // L'UI se met a jour immediatement
    addOptimisticTodo(newTodo);

    // Le serveur traite en arriere-plan
    await addTodo(newTodo);
  }

  return (
    <form action={handleAdd}>
      <input name="text" />
      <ul>
        {optimisticTodos.map(todo => (
          <li
            key={todo.id}
            style={{ opacity: todo.pending ? 0.5 : 1 }}
          >
            {todo.text}
          </li>
        ))}
      </ul>
    </form>
  );
}

Migration de React 19 Vers 20

La migration est relativement fluide, mais il y a des points d'attention.

Breaking Changes

// 1. forwardRef n'est plus necessaire
// Avant
const Input = forwardRef((props, ref) => (
  <input ref={ref} {...props} />
));

// Apres
function Input({ ref, ...props }) {
  return <input ref={ref} {...props} />;
}

// 2. Context comme provider direct
// Avant
<ThemeContext.Provider value={theme}>

// Apres
<ThemeContext value={theme}>

Checklist de Migration

# 1. Mettez a jour les dependances
npm install react@20 react-dom@20

# 2. Mettez a jour les types TypeScript
npm install @types/react@20

# 3. Executez les codemods
npx @react-codemod/update-react-imports

# 4. Verifiez les depreciations
npx react-upgrade-check

React Server Components Matures

Les RSC sont passes d'experimental a standard de production.

Architecture Recommandee

app/
├── layout.jsx          # Server Component
├── page.jsx            # Server Component
├── components/
│   ├── Header.jsx      # Server Component
│   ├── Footer.jsx      # Server Component
│   └── client/
│       ├── Form.jsx    # 'use client'
│       └── Modal.jsx   # 'use client'
└── actions/
    └── submit.js       # 'use server'

Regle d'Or

// Par defaut: Server Components
// - Pas besoin de directive
// - Peuvent acceder a la base de donnees directement
// - N'ajoutent pas de JS au bundle client

// Client Components: uniquement quand necessaire
// - Interactivite (onClick, onChange)
// - Hooks navigateur (useState, useEffect)
// - APIs du navigateur (localStorage, etc)

'use client' // Uniquement quand c'est vraiment necessaire

Performance: Chiffres Reels

Comparatifs de projets migres vers React 20.

Bundle Size

React 19: 142 KB (gzipped)
React 20: 128 KB (gzipped)

Reduction: 10%

Core Web Vitals (Moyenne)

Metrique   | React 19 | React 20 | Amelioration
-----------|----------|----------|-------------
LCP        | 2.1s     | 0.9s     | -57%
FID        | 95ms     | 42ms     | -56%
CLS        | 0.12     | 0.05     | -58%
INP        | 180ms    | 75ms     | -58%

Utilisation Memoire

Application moyenne:
React 19: 45MB heap
React 20: 32MB heap

Reduction: 29%

Ce Qui Arrive Ensuite

React 20 n'est que le debut. La feuille de route indique :

React 21 (Preview)

- Activity API (remplace StrictMode)
- Support natif des animations
- Ameliorations de Suspense
- Rendu hors ecran

Ecosysteme

- Next.js 16 avec PPR par defaut
- Remix adoption complete des RSC
- React Native avec nouvelle architecture

Conclusion

React 20 n'est pas seulement une mise a jour, c'est une reimagination de la facon dont nous construisons des applications web. Les Server Actions eliminent le boilerplate, le PPR met fin aux ecrans blancs, et le Compiler supprime la complexite de l'optimisation manuelle.

Pour les developpeurs, cela signifie un code plus simple et de meilleures performances. Pour les utilisateurs, cela signifie des applications plus rapides et reactives.

Si vous n'avez pas encore commence a migrer, c'est le moment. Le futur de React est server-first, streaming-enabled et automatiquement optimise.

Si vous souhaitez continuer a suivre les nouveautes de l'ecosysteme, je recommande de jeter un oeil a un autre article : TypeScript 7 Natif en Go: 10x Plus Rapide ou nous explorons un autre grand changement qui transforme le developpement frontend.

Allons-y! 🦅

Commentaires (0)

Cet article n'a pas encore de commentaires. Soyez le premier!

Ajouter des commentaires