Menu

Questions d'entretien React et réponses (React 19)

Une trentaine de questions d'entretien React, du niveau débutant au niveau avancé, chacune avec une réponse courte qu'un recruteur accepterait et du code exécutable pour celles qu'il vaut mieux voir que lire.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Voici les questions d'entretien React qui reviennent le plus souvent, regroupées par niveau et traitées comme un recruteur l'attend : courtes, correctes pour React 19, et avec la raison derrière la règle. Quand voir le comportement vaut mieux que le lire, la réponse comporte un éditeur en direct, et quelques questions vous demandent de prédire la sortie de la console avant de lancer le code.

Avant de cliquer : qu'affiche la console sous l'aperçu, et qu'affiche le bouton ? La réponse se trouve dans la section débutant ci-dessous.

Questions de niveau débutant

Qu'est-ce que React ?

React est une bibliothèque JavaScript pour construire des interfaces utilisateur à partir de composants. Vous écrivez des fonctions qui renvoient une description de l'interface pour les données actuelles, et quand ces données changent, React détermine ce qui a changé et met à jour le DOM pour vous. Il ne gère que la couche vue : le routage, la récupération de données et les formulaires viennent d'autres bibliothèques ou d'un framework comme Next.js.

Qu'est-ce que le JSX ?

Le JSX est une extension de syntaxe qui permet d'écrire du balisage dans du JavaScript. Un compilateur (Babel, esbuild, SWC) transforme chaque balise en un appel qui crée un élément React, donc <p className="note">{text}</p> devient un objet avec type: 'p' et les props. Comme c'est du JavaScript, vous utilisez className au lieu de class, placez les expressions entre {}, et chaque balise doit être fermée. La page sur le JSX détaille les règles.

Quelle est la différence entre un composant et un élément ?

Un composant est une fonction (ou une classe) qui prend des props et renvoie de l'interface. Un élément est l'objet simple que produit le JSX, qui décrit quoi afficher : <Avatar size={40} /> est un élément dont le type est la fonction Avatar. React appelle votre composant pour transformer des éléments en d'autres éléments, jusqu'aux balises DOM. Les éléments sont peu coûteux et immuables ; vous n'appelez jamais vous-même un composant.

Quelle est la différence entre props et état ?

Les props sont passées par le parent et sont en lecture seule dans le composant. L'état appartient au composant, change au fil du temps par un setter, et chaque changement planifie un nouveau rendu. Une façon courante de le dire : les props configurent un composant, l'état est sa mémoire. La même valeur peut être un état dans un parent et une prop dans son enfant.

Qu'affiche le premier exemple de cette page ?

Il affiche logged: 0, et le bouton affiche Count: 1, pas 2. L'état est un instantané : count est une constante pendant tout le rendu, donc les deux appels setCount(count + 1) calculent 0 + 1, et le message lit l'ancienne valeur car la nouvelle n'existe qu'au rendu suivant. Pour ajouter deux, utilisez la forme fonction de mise à jour : setCount((c) => c + 1) deux fois.

Pourquoi les listes ont-elles besoin de keys, et pourquoi l'index est-il une mauvaise key ?

React utilise la key pour associer chaque élément de la liste à celui du rendu précédent. Si vous utilisez l'index du tableau et insérez un élément en tête, tous les index se décalent, donc React garde l'état de chaque ligne à son ancienne position et l'attache aux mauvaises données.

Cochez Ada, puis cliquez sur "Add to top" : la coche saute sur la nouvelle première ligne. Remplacez key={index} par key={person.id} et réessayez : la coche reste avec Ada. En développement, React avertit aussi quand des keys manquent ; l'aperçu fonctionne comme un build de production, vous ne verrez donc pas cet avertissement ici.

Qu'est-ce qu'un champ contrôlé ?

Un champ dont la valeur vient de l'état React : vous passez value et mettez à jour l'état dans onChange, React est donc la seule source de vérité et vous pouvez valider ou transformer chaque frappe. Un champ non contrôlé garde sa propre valeur dans le DOM et vous la lisez quand vous en avez besoin, via une ref ou le FormData du formulaire. Les champs contrôlés sont le choix par défaut quand l'interface réagit à ce que tape l'utilisateur.

Que signifie faire remonter l'état ?

Quand deux composants ont besoin des mêmes données, vous déplacez l'état dans leur parent commun le plus proche et le passez vers le bas en props, avec une fonction pour le modifier. Les enfants cessent de posséder leurs propres copies, ils ne peuvent donc jamais se contredire. C'est la réponse standard à « comment des composants frères partagent-ils un état », avant de recourir au contexte ou à un store.

Quelles sont les règles des hooks ?

N'appelez les hooks qu'au niveau supérieur d'un composant ou d'un hook personnalisé, jamais dans des conditions, des boucles ou des fonctions imbriquées, et uniquement depuis des fonctions React, pas depuis de simples fonctions JavaScript. React identifie chaque hook par l'ordre des appels, cet ordre doit donc être identique à chaque rendu. Le paquet eslint-plugin-react-hooks fait respecter les deux règles.

Qu'est-ce qu'un fragment ?

Un fragment regroupe plusieurs éléments sans ajouter de nœud DOM : <>...</>, ou <Fragment key={id}> quand vous avez besoin d'une key dans une liste. Un composant doit renvoyer une seule racine, et les fragments permettent à cette racine d'être plusieurs éléments frères, ce qui compte dans les tableaux et les mises en page flex où une div supplémentaire casserait le balisage.

Questions de niveau intermédiaire

Comment fonctionne le tableau de dépendances de useEffect ?

React exécute l'effet une fois le rendu commité (généralement après l'affichage par le navigateur), puis à nouveau après tout rendu ultérieur dans lequel une valeur du tableau a changé (comparée avec Object.is). Sans tableau, il s'exécute après chaque rendu ; avec [], une fois après le premier rendu. Chaque valeur du composant que l'effet lit a sa place dans le tableau, et le linter vous signale quand l'une d'elles manque.

Quand le nettoyage d'un effet s'exécute-t-il ?

La fonction que vous renvoyez depuis un effet s'exécute avant que l'effet s'exécute à nouveau avec de nouvelles dépendances, et une fois au démontage du composant. C'est là que vous défaites ce que l'effet a mis en place : arrêter un minuteur, retirer un écouteur, fermer une connexion.

Cliquez sur "Switch room" et regardez la console : le nettoyage de l'ancien salon s'exécute d'abord, puis l'effet se connecte au nouveau. "Hide chat" n'exécute que le nettoyage. En développement, StrictMode ajoute au montage une séquence supplémentaire connexion, déconnexion, connexion pour vérifier que votre nettoyage fonctionne ; l'aperçu fonctionne comme un build de production, vous ne voyez donc que la vraie séquence.

Pourquoi mon état semble-t-il périmé dans setInterval ?

Le callback de l'intervalle est une closure sur le count du rendu qui l'a créé. Avec un tableau de dépendances vide, l'effet ne s'exécute plus jamais, donc le callback continue de lire ce premier count pour toujours.

broken atteint 1 et s'arrête, car chaque tic calcule 0 + 1. fixed continue de compter, car la fonction de mise à jour reçoit la dernière valeur. Ajouter broken au tableau de dépendances fonctionne aussi, au prix d'un intervalle effacé et recréé chaque seconde.

Qu'est-ce que le batching ?

React regroupe plusieurs mises à jour d'état en un seul rendu. Depuis React 18, cela s'applique partout : gestionnaires d'événements, timeouts, promesses et écouteurs d'événements natifs. Si vous avez besoin que le DOM soit mis à jour immédiatement après une mise à jour, flushSync de react-dom permet d'y échapper, mais c'est rarement nécessaire.

Le clic affiche un seul render 1 1 1, pas trois rendus. Avant React 18, trois mises à jour d'état dans un timeout signifiaient trois rendus.

Qu'affiche ce code ? (ordre des effets)

Lisez le code et notez les quatre lignes que la console affichera, dans l'ordre, avant de la regarder.

Le rendu va de haut en bas : render App, puis render Child. Les effets s'exécutent de bas en haut, une fois tout l'arbre commité : effect Child, puis effect App. L'effet d'un parent peut compter sur le fait que les effets de ses enfants se sont déjà exécutés.

Quelle est la différence entre useMemo et useCallback ?

useMemo(() => compute(a, b), [a, b]) met en cache le résultat d'un calcul. useCallback(fn, [deps]) met en cache la fonction elle-même, c'est donc la même chose que useMemo(() => fn, [deps]). Les deux n'aident que lorsque quelque chose en aval compare par référence : un enfant memo, ou le tableau de dépendances d'un autre hook. Depuis React Compiler 1.0 (octobre 2025), une étape de build peut ajouter cette mémoïsation automatiquement, mais la mémoïsation manuelle fonctionne toujours et vous la verrez encore dans la plupart des bases de code.

Que fait React.memo, et pourquoi a-t-il souvent besoin de useCallback ?

memo(Component) saute le nouveau rendu du composant quand ses props sont les mêmes que la fois précédente, comparées une par une avec Object.is. Une fonction écrite inline dans le parent est une nouvelle fonction à chaque rendu, elle compte donc comme une prop modifiée et annule memo. useCallback garde la même fonction d'un rendu à l'autre.

Videz la console et cliquez sur "Re-render parent" : seul render inline handler apparaît. L'autre enfant a reçu la même fonction et a été sauté. Retirez memo(...) autour de Button et les deux écrivent à chaque clic, ce qui montre que useCallback seul ne fait rien.

Qu'est-ce que le contexte, et que coûte-t-il ?

Le contexte transmet une valeur à chaque composant sous un provider sans la faire passer par les props : createContext, puis <ThemeContext value={theme}> dans React 19 (ou <ThemeContext.Provider>), et useContext(ThemeContext) pour la lire. Le coût, c'est que chaque composant qui lit le contexte refait son rendu quand la valeur change, et memo ne l'en empêche pas. Gardez-le peu coûteux en séparant les valeurs sans rapport dans des contextes distincts, en enveloppant une valeur objet dans useMemo et en gardant l'état qui change vite hors du contexte global de l'application. Voir useContext.

Que sont les refs, et quand en utiliser une plutôt que l'état ?

useRef(initial) renvoie un objet dont la propriété current persiste d'un rendu à l'autre, et la modifier ne déclenche pas de rendu. Utilisez une ref pour les valeurs dont l'écran ne dépend pas (un identifiant de minuteur, la valeur précédente, un indicateur) et pour l'accès au DOM (<input ref={inputRef}> puis inputRef.current.focus()). Si la valeur est affichée à l'écran, elle a sa place dans l'état.

Qu'est-ce que le DOM virtuel, et qu'est-ce que la réconciliation ?

À chaque rendu, React construit un nouvel arbre d'éléments et le compare au précédent ; cette comparaison est la réconciliation. Si le type d'un élément a changé (une div est devenue une section, ou ProfileA est devenu ProfileB), React détruit ce sous-arbre et son état et en construit un nouveau. Si le type est le même, il garde le nœud DOM et met à jour les props modifiées, et il utilise les keys pour associer les enfants dans les listes. « DOM virtuel » est le nom courant de cet arbre en mémoire ; la rapidité vient du fait de ne toucher qu'à ce qui a changé, pas de la rapidité de l'arbre lui-même.

Qu'est-ce qu'un hook personnalisé ?

Une fonction dont le nom commence par use et qui appelle d'autres hooks, pour réutiliser une logique avec état entre composants : useOnlineStatus, useLocalStorage, useDebouncedValue. Chaque composant qui l'appelle obtient son propre état indépendant ; un hook personnalisé partage la logique, pas les données. Voir hooks personnalisés.

Que fait StrictMode ?

<StrictMode> active des vérifications supplémentaires en développement uniquement. Il fait le rendu des composants deux fois pour révéler les rendus impurs, exécute au montage la séquence mise en place, nettoyage, mise en place des effets pour révéler les nettoyages manquants, fait de même pour les ref callbacks, et avertit au sujet des API obsolètes. Rien de tout cela n'arrive dans un build de production, donc un double message dans la console en développement est normal et n'est pas un bug.

Questions de niveau avancé

Qu'affiche ce code ? (rendu, effet de layout, effet)

Une dernière prédiction. Trois messages, trois moments différents d'un rendu.

L'ordre est : le rendu, puis useLayoutEffect, puis useEffect, même si useEffect est écrit en premier. Les effets de layout s'exécutent après la mise à jour du DOM par React mais avant l'affichage par le navigateur, c'est pourquoi ils conviennent pour mesurer un élément ; les effets ordinaires s'exécutent plus tard, généralement après l'affichage, et doivent être le choix par défaut.

Qu'est-ce qu'une error boundary ?

Un composant classe qui intercepte les erreurs levées pendant le rendu de ses enfants et affiche un contenu de repli au lieu de démonter toute l'application. Il lui faut static getDerivedStateFromError (pour passer au contenu de repli) et généralement componentDidCatch (pour journaliser). Il n'existe toujours pas d'équivalent en hook, donc dans les bases de code à base de composants fonctions, les équipes écrivent une classe ou utilisent le paquet react-error-boundary.

Cliquez sur "Break it" : le contenu de repli ne remplace que les enfants de la boundary, le bouton reste, et React signale quand même l'erreur interceptée dans la console. Les boundaries n'interceptent pas les erreurs dans les gestionnaires d'événements, dans le code async comme setTimeout, ni dans la boundary elle-même. Pour ces cas, vous utilisez try/catch et modifiez l'état.

Qu'est-ce qu'un portail ?

createPortal(children, domNode) de react-dom affiche des enfants dans un autre nœud DOM, généralement document.body, tout en les gardant à la même place dans l'arbre React. Les modales, les infobulles et les notifications l'utilisent pour échapper au overflow: hidden ou au contexte d'empilement d'un parent. Le contexte fonctionne toujours à travers un portail, et les événements remontent à travers l'arbre React, donc un clic dans le portail atteint le onClick du parent même si les nœuds DOM sont ailleurs. Voir portails.

Que sont Suspense et lazy ?

lazy(() => import('./Chart')) charge le code d'un composant à son premier rendu, ce qui découpe votre bundle. <Suspense fallback={<Spinner />}> affiche le contenu de repli tant que quelque chose à l'intérieur est encore en chargement : du code lazy, ou des données lues avec use(promise) ou un framework compatible avec Suspense. L'emplacement des frontières décide quelles parties de la page attendent ensemble.

import { lazy, Suspense } from 'react';

const Chart = lazy(() => import('./Chart.jsx'));

export default function Dashboard() {
    return (
        <Suspense fallback={<p>Loading chart...</p>}>
            <Chart />
        </Suspense>
    );
}

Que fait useTransition ?

Il marque une mise à jour d'état comme non urgente. const [isPending, startTransition] = useTransition() et startTransition(() => setTab('posts')) permettent à React de garder l'écran actuel réactif et d'interrompre le rendu lent si une mise à jour plus urgente arrive, comme une frappe. isPending vous indique d'afficher une indication. Dans React 19, la fonction que vous passez peut être async, ce que React appelle une action. Ne l'utilisez pas pour mettre à jour la valeur propre d'un champ texte ; cette mise à jour doit être urgente.

Que sont les React Server Components ?

Des composants qui s'exécutent uniquement sur le serveur (ou au moment du build) et envoient leur résultat rendu au navigateur, jamais leur code. Ils peuvent être async et lire directement une base de données ou le système de fichiers, mais ils ne peuvent utiliser ni état, ni effets, ni API du navigateur. Un fichier marqué 'use client' ouvre une frontière client où vivent les composants interactifs, et 'use server' marque des fonctions serveur que le code client peut appeler. Vous les utilisez via un framework comme Next.js avec l'App Router ; les simples applications Vite n'ont pas de serveur pour les exécuter.

Qu'est-ce qui a changé dans React 19 ?

  • Actions : des fonctions async dans des transitions, avec l'état d'attente géré pour vous. Un <form action={fn}> appelle fn avec le FormData du formulaire.
  • Nouveaux hooks : useActionState pour le résultat et l'état d'attente d'un formulaire, useOptimistic pour l'interface optimiste, et useFormStatus dans react-dom.
  • use : lit une promesse (en se suspendant jusqu'à sa résolution) ou un contexte, et contrairement aux autres hooks, il peut être appelé dans une condition.
  • ref en prop : les composants fonctions reçoivent ref comme n'importe quelle autre prop, donc forwardRef n'est plus nécessaire pour le nouveau code. Les ref callbacks peuvent renvoyer une fonction de nettoyage.
  • <Context> comme provider, plus les balises <title> et <meta> qui remontent dans le head du document.
  • Suppressions : ReactDOM.render, les string refs, le contexte legacy et defaultProps sur les composants fonctions (utilisez des paramètres par défaut).
// React 19: ref is a normal prop
function TextInput({ ref, ...props }) {
    return <input ref={ref} {...props} />;
}

La page sur React 19 propose des exemples exécutables de chacun.

Comment tester des composants React ?

Avec React Testing Library et un exécuteur comme Vitest ou Jest. Vous affichez le composant, trouvez les éléments comme le ferait un utilisateur (par rôle, libellé ou texte), interagissez avec user-event, et vérifiez ce qui est visible, pas l'état interne. Les tests restent ainsi valides au fil des refactorisations.

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

test('counts clicks', async () => {
    const user = userEvent.setup();
    render(<Counter />);
    await user.click(screen.getByRole('button', { name: /clicked 0 times/i }));
    expect(screen.getByRole('button')).toHaveTextContent('Clicked 1 times');
});

toHaveTextContent vient de @testing-library/jest-dom. Pour des parcours complets sur plusieurs pages, les équipes ajoutent Playwright ou Cypress par-dessus.

Comment trouver et corriger un problème de performance ?

Mesurez d'abord. Ouvrez l'onglet Profiler des React DevTools, enregistrez l'interaction lente et lisez le flame chart : il montre quels composants ont fait leur rendu, combien de temps chacun a pris et (avec le réglage « record why each component rendered ») pourquoi. Les corrections typiques, dans l'ordre où les essayer : descendre l'état pour que moins de composants en dépendent, passer les sous-arbres lents via children, mémoïser la partie coûteuse avec memo, useMemo et useCallback, virtualiser les longues listes, et différer les mises à jour lourdes avec useTransition ou useDeferredValue. Profilez sur un build de production ou de profilage ; les builds de développement sont plus lents et exagèrent les temps de rendu.

Pourquoi un composant doit-il être pur ?

Avec les mêmes props, le même état et le même contexte, un composant doit renvoyer le même JSX et ne rien modifier en dehors de lui pendant le rendu. React peut faire le rendu d'un composant plus d'une fois, dans le désordre, ou jeter un rendu (transitions, Suspense, StrictMode), donc les effets de bord dans le corps, comme muter une variable ou envoyer une requête, s'exécutent un nombre imprévisible de fois. Les effets de bord ont leur place d'abord dans les gestionnaires d'événements, et dans les effets quand aucun événement ne les a causés.

Quand ne pas utiliser d'effet ?

Quand la valeur peut être calculée pendant le rendu (listes filtrées, noms complets, totaux), quand le travail est causé par une action de l'utilisateur (placez-le dans le gestionnaire d'événement), et quand vous voulez réinitialiser l'état lors d'un changement de prop (utilisez une key). Les effets servent à se synchroniser avec quelque chose d'extérieur à React : une connexion réseau, une API du navigateur, un widget tiers. Les chaînes d'effets qui modifient l'état sont une source fréquente de rendus en trop et de bugs.

Questions fréquentes

Qu'est-ce que React ?

React est une bibliothèque JavaScript pour construire des interfaces utilisateur à partir de composants. Vous décrivez à quoi l'écran doit ressembler pour les données actuelles, et React met à jour le vrai DOM quand ces données changent.

Quelle est la différence entre état et props ?

Les props sont des entrées qu'un parent passe à un composant, et le composant les traite comme en lecture seule. L'état est une donnée que le composant possède et qui change au fil du temps grâce à un setter, ce qui fait refaire un rendu par React.

Que sont les hooks dans React ?

Les hooks sont des fonctions dont le nom commence par use et qui permettent à un composant fonction d'utiliser les fonctionnalités de React : useState pour l'état, useEffect pour les effets de bord, useContext pour le contexte, useRef pour des valeurs qui ne déclenchent pas de rendu, et d'autres.

Qu'est-ce que le DOM virtuel ?

C'est le nom donné à la description en mémoire de l'interface par React. À chaque rendu, React construit une nouvelle description, la compare à la précédente et n'applique au vrai DOM que les différences. Cette comparaison s'appelle la réconciliation.

Pourquoi les keys sont-elles importantes dans les listes React ?

Une key indique à React quel élément d'une liste est lequel d'un rendu à l'autre. Avec des keys stables (comme un identifiant), React garde l'état et le nœud DOM de chaque élément attachés aux bonnes données quand des éléments sont ajoutés, retirés ou réordonnés. Utiliser l'index du tableau casse cela quand l'ordre change.

Qu'est-ce que le JSX ?

Le JSX est une extension de syntaxe qui permet d'écrire un balisage proche du HTML dans du JavaScript. Un compilateur transforme chaque balise en un appel de fonction qui crée un élément React, donc <h1>Hi</h1> devient un simple objet qui décrit un h1.

Illustration des langages de programmation de Coddy

Apprendre à coder avec Coddy

COMMENCER