Quelle est la nouveauté la plus révolutionnaire de React 19 ?
Le React Compiler (anciennement React Forget).
Il ajoute automatiquement la mémoïsation à votre code. Plus besoin de :
- useMemo
- useCallback
- memo
Avant (React 18) :
const sorted = useMemo(() => items.sort(), [items]); const handleClick = useCallback(() => onClick(id), [onClick, id]); export default memo(MyComponent);
Après (React 19) :
const sorted = items.sort(); const handleClick = () => onClick(id); export default MyComponent;
Le compiler optimise mieux qu’un humain et ne peut pas oublier !
Quel est le mnémonique CAFÉ PLUS pour React 19 ?
CAFÉ PLUS (React 19 vous donne un boost !) :
Phrase : “Prenez un CAFÉ PLUS pour coder avec React 19 !”
Que retourne useActionState et comment l’utiliser ?
useActionState retourne [state, formAction, isPending].
Signature :
const [state, formAction, isPending] = useActionState( actionFunction, initialState );
Exemple complet :
```
async function subscribe(prevState, formData) {
const email = formData.get(‘email’);
try {
await api.subscribe(email);
return { success: true, error: null };
} catch (err) {
return { success: false, error: err.message };
}
}
function Form() {
const [state, action, isPending] = useActionState(subscribe, {
success: false,
error: null
});
return (
<form action={action}>
<input name=”email” disabled={isPending} />
<button disabled={isPending}>
{isPending ? ‘Envoi…’ : ‘S\‘inscrire’}
</button>
{state.error && <p>{state.error}</p>}
</form>
);
}
~~~
Comment fonctionne le hook use() de React 19 ?
use() lit des Promises ou Contexts directement dans le rendu.
Lire une Promise :
```
function UserCard({ userPromise }) {
const user = use(userPromise); // Suspend jusqu’à résolution
return <h1>{user.name}</h1>;
}
// OBLIGATOIRE : Suspense parent
<Suspense fallback={<Spinner></Spinner>}>
<UserCard userPromise={fetchUser(1)} />
</Suspense>
```
Lire un Context (conditionnellement !) :
function Button({ showTheme }) {
if (showTheme) {
const theme = use(ThemeContext); // OK !
return <button className={theme}>Btn</button>;
}
return <button>Default</button>;
}Différence avec useContext : use() peut être appelé conditionnellement !
Comment passer une ref en React 19 sans forwardRef ?
ref est maintenant une prop normale !
Avant (React 18) :
```
import { forwardRef } from ‘react’;
const Input = forwardRef(function Input(props, ref) {
return <input ref={ref} {…props} />;
});
```
Après (React 19) :
function Input({ ref, ...props }) {
return <input ref={ref} {...props} />;
}Utilisation (identique) :
function Form() {
const inputRef = useRef(null);
return <Input ref={inputRef} />;
}Note : forwardRef sera déprécié dans une future version. Un codemod existe pour migrer.
Comment fonctionne useFormStatus ?
useFormStatus accède à l’état du formulaire PARENT.
IMPORTANT : Doit être dans un composant ENFANT du form !
```
import { useFormStatus } from ‘react-dom’;
function SubmitButton() {
const { pending, data, method, action } = useFormStatus();
return (
<button disabled={pending}>
{pending ? ‘Envoi…’ : ‘Envoyer’}
</button>
);
}
function ContactForm() {
return (
<form action={sendMessage}>
<input></input>
<SubmitButton></SubmitButton> {/* Doit être ENFANT du form */}
</form>
);
}
```
Retourne :
- pending : boolean (action en cours)
- data : FormData soumis
- method : ‘get’ ou ‘post’
- action : référence à l’action
Comment fonctionne useOptimistic ?
useOptimistic affiche un état optimiste pendant une action async.
```
import { useOptimistic } from ‘react’;
function TodoList({ todos, addTodo }) {
const [optimisticTodos, addOptimistic] = useOptimistic(
todos,
(current, newTodo) => […current, { …newTodo, pending: true }]
);
async function handleAdd(formData) {
const title = formData.get(‘title’);
// 1. Affiche immédiatement (optimiste)
addOptimistic({ id: Date.now(), title });
// 2. Puis exécute l'action réelle
await addTodo({ title }); }return (
<ul>
{optimisticTodos.map(todo => (
<li style={{ opacity: todo.pending ? 0.5 : 1 }}>
{todo.title}
</li>
))}
</ul>
);
}
```
Si l’action échoue : L’état optimiste disparaît automatiquement !
Comment utiliser les métadonnées de document en React 19 ?
React 19 hoist automatiquement <title>, <meta>, <link> vers <head>.
```
function BlogPost({ post }) {
return (
<article>
{/* Hoistés automatiquement vers <head> */}
<title>{post.title} - Mon Blog</title>
<meta name=”description” content={post.excerpt} />
<meta property=”og:title” content={post.title} />
<link rel=”canonical” href={/posts/${post.slug}} />
<h1>{post.title}</h1>
<p>{post.content}</p>
</article> ); } ```Avantages :
- Plus besoin de react-helmet
- Fonctionne avec SSR et Suspense
- Gère les doublons automatiquement
- Chaque composant gère ses métadonnées
Quel est le problème avec ce code React 19 ?
```
function UserProfile({ userId }) {
const user = use(
fetch(/api/users/${userId}).then(r => r.json())
);
return <h1>{user.name}</h1>;
}
~~~
Problème : Nouvelle Promise à chaque rendu = boucle infinie !
Explication :
1. use() suspend le composant
2. Au re-render, nouvelle Promise créée
3. use() suspend à nouveau
4. Boucle infinie !
Solution 1 : Passer la Promise en prop
```
function UserProfile({ userPromise }) {
const user = use(userPromise);
return <h1>{user.name}</h1>;
}
// Parent crée la Promise une seule fois
<UserProfile userPromise={fetchUser(1)} />
```
Solution 2 : Utiliser un cache
```
const cache = new Map();
function getUser(id) {
if (!cache.has(id)) {
cache.set(id, fetch(/api/users/${id}).then(r => r.json()));
}
return cache.get(id);
}
function UserProfile({ userId }) {
const user = use(getUser(userId));
return <h1>{user.name}</h1>;
}
~~~
Comment utiliser Context sans .Provider en React 19 ?
React 19 permet de rendre le Context directement !
Avant (React 18) :
```
const ThemeContext = createContext(‘light’);
function App() {
return (
<ThemeContext.Provider>
<Content></Content>
</ThemeContext.Provider>
);
}
```
Après (React 19) :
```
const ThemeContext = createContext(‘light’);
function App() {
return (
<ThemeContext>
<Content></Content>
</ThemeContext>
);
}
```
Note : .Provider sera déprécié dans une future version mais reste fonctionnel pour la compatibilité.
Comment fonctionnent les fonctions de cleanup dans les refs ?
React 19 : Les refs peuvent retourner une fonction de cleanup !
Avant (React 18) :
```
function Video({ src }) {
const videoRef = useRef(null);
useEffect(() => {
videoRef.current?.play();
return () => {
videoRef.current?.pause();
};
}, []);
return <video ref={videoRef} src={src} />;
}
```
Après (React 19) :
```
function Video({ src }) {
return (
<video
ref={(video) => {
if (video) video.play();
// Cleanup function !
return () => {
if (video) video.pause();
};
}}
src={src}
/> ); } ```Avantage : Plus besoin de useEffect + useRef pour des setups/cleanups simples !
Quelles sont les APIs de préchargement de React 19 ?
Nouvelles fonctions dans react-dom :
```
import {
prefetchDNS,
preconnect,
preload,
preinit
} from ‘react-dom’;
function App() {
// 1. Pré-résoudre le DNS
prefetchDNS(‘https://api.example.com’);
// 2. Établir connexion TCP/TLS
preconnect(‘https://api.example.com’);
// 3. Télécharger sans exécuter
preload(‘/fonts/roboto.woff2’, {
as: ‘font’,
type: ‘font/woff2’
});
// 4. Télécharger ET exécuter/appliquer
preinit(‘/scripts/analytics.js’, { as: ‘script’ });
return <Content></Content>;
}
```
Différences :
- prefetchDNS → DNS seulement
- preconnect → DNS + TCP + TLS
- preload → Télécharge (pas d’exécution)
- preinit → Télécharge + exécute/applique
Comment gérer les stylesheets avec precedence en React 19 ?
React 19 gère nativement les stylesheets avec priorité.
```
function ProductPage({ product }) {
return (
<>
{/* Haute priorité - bloque le rendu */}
<link></link>
{/* Priorité moyenne */}
<link
rel="stylesheet"
href="/styles/product.css"
precedence="medium"
/>
{/* Basse priorité */}
<link
rel="stylesheet"
href="/styles/reviews.css"
precedence="low"
/>
<ProductContent />
</> ); } ```precedence contrôle :
- L’ordre d’insertion dans <head>
- Le groupement des stylesheets
- Évite les problèmes de spécificité CSS
React déduplique automatiquement les stylesheets identiques !
Quelle est la différence entre useActionState et useFormStatus ?
Tableau comparatif :
useActionState - Définit et gère l’action :
```
const [state, action, isPending] = useActionState(
myAction,
initialState
);
return <form action={action}>…</form>;
```
useFormStatus - Lit l’état du form parent :
```
function SubmitBtn() {
const { pending } = useFormStatus();
return <button disabled={pending}>Submit</button>;
}
// DOIT être enfant du form
<form action={…}>
<SubmitBtn></SubmitBtn>
</form>
~~~
Aspect | useActionState | useFormStatus |
|——–|—————-|—————|
| Import | react | react-dom |
| Retourne | [state, action, isPending] | { pending, data, method } |
| Usage | Définir l’action | Lire l’état du form |
| Placement | N’importe où | ENFANT du form |
Comment migrer un composant React 18 vers React 19 avec les Actions ?
Migration d’un formulaire classique vers Actions :
Avant (React 18) :
```
function Form() {
const [value, setValue] = useState(‘’);
const [isPending, setIsPending] = useState(false);
const [error, setError] = useState(null);
async function handleSubmit(e) {
e.preventDefault();
setIsPending(true);
try {
await submitData(value);
} catch (err) {
setError(err.message);
} finally {
setIsPending(false);
}
}
return (
<form onSubmit={handleSubmit}>
<input value={value} onChange={e => setValue(e.target.value)} />
<button disabled={isPending}>Submit</button>
</form>
);
}
```
Après (React 19) :
```
async function submitAction(prev, formData) {
try {
await submitData(formData.get(‘value’));
return { error: null };
} catch (err) {
return { error: err.message };
}
}
function Form() {
const [state, action, isPending] = useActionState(submitAction, { error: null });
return (
<form action={action}>
<input></input>
<button disabled={isPending}>Submit</button>
{state.error && <p>{state.error}</p>}
</form>
);
}
~~~