Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Mises à jour basées sur la priorité — rendu urgent vs non-urgent avec startTransition.
useTransition est un hook React 18 qui vous permet de marquer les mises à jour de state comme 'transitions non urgentes'. Les mises à jour urgentes (frappe, clic) sont traitées immédiatement et ne sont jamais interrompues. Les mises à jour de transition sont de priorité inférieure — si une mise à jour urgente arrive pendant qu'une transition est en cours, React interrompt la transition, traite le travail urgent, puis redémarre la transition. Cela maintient l'interface réactive même pendant les re-rendus lourds.
Le planificateur React assigne à chaque mise à jour une lane de priorité : SyncLane (urgent, non groupable), InputContinuousLane (glisser/défilement), DefaultLane (setState normal) et TransitionLane (useTransition / startTransition). Les lanes de priorité plus élevée préemptent toujours les lanes inférieures.
Envelopper un appel setState dans startTransition(callback) dit à React : 'cette mise à jour est une transition — elle peut être interrompue'. React la planifie dans une TransitionLane et maintient l'interface courante visible jusqu'à ce que la transition se termine.
Si l'utilisateur tape un autre caractère pendant qu'une liste de 5000 éléments se re-rend en tant que transition, React met en pause le rendu de transition au milieu de l'arbre, traite immédiatement la frappe (urgente), met à jour l'entrée, puis redémarre la transition depuis le début avec la nouvelle valeur d'entrée.
useTransition retourne [isPending, startTransition]. isPending est true pendant que React traite la mise à jour de transition. Utilisez-le pour afficher un indicateur de chargement discret sans bloquer l'interface.
Une alternative à startTransition : useDeferredValue(value) retourne une copie différée de value qui est en retard pendant les transitions. L'interface se rend d'abord avec l'ancienne valeur différée (rapide), puis se re-rend avec la nouvelle valeur lorsque React a le temps.
Une lane de planificateur basse priorité pour les mises à jour de transition. Peut être préemptée par tout travail de priorité plus élevée (entrée utilisateur, mises à jour synchrones).
Marque les appels setState à l'intérieur de son callback comme non urgents. Disponible comme import autonome ou depuis le hook useTransition.
Booléen de useTransition. True pendant que React traite encore la mise à jour de transition. À utiliser pour afficher un spinner sans bloquer l'entrée.
Retourne une copie différée d'une valeur. Se rend d'abord avec la valeur périmée (instantané), se re-rend avec la valeur fraîche lorsque inactif. Utile pour filtrer de grandes listes.
Lorsqu'une mise à jour urgente arrive au milieu d'une transition, React abandonne le rendu de transition en cours et le redémarre à neuf après avoir traité le travail urgent.
1import { useState, useTransition } from 'react';23function SearchPage() {4 const [query, setQuery] = useState('');5 const [results, setResults] = useState(allItems);6 const [isPending, startTransition] = useTransition();78 function handleChange(e) {9 // Urgent: update the input immediately (never interrupted)10 setQuery(e.target.value);1112 // Non-urgent: filter 10,000 items as a transition13 startTransition(() => {14 setResults(allItems.filter(item =>15 item.name.includes(e.target.value)16 ));17 });18 }1920 return (21 <>22 <input value={query} onChange={handleChange} />23 {isPending && <Spinner />} {/* subtle loading indicator */}24 <ResultsList items={results} />25 </>26 );27}
Avant les transitions, React rendait toutes les mises à jour de state à la même priorité — un re-rendu de liste lourd pouvait geler l'entrée pendant des centaines de millisecondes. Les transitions vous permettent de dire explicitement à React 'l'utilisateur a besoin que l'entrée se sente instantanée, mais la liste de résultats peut prendre un moment'. C'est la différence entre une application lente et une application fluide lorsqu'on traite des rendus coûteux.
A dashboard has tabs: Overview, Analytics, Reports. Clicking 'Analytics' loads heavy chart components. Without transitions, the current tab disappears immediately and the user sees a loading blank until the new tab renders.
The tab switch calls `setActiveTab('analytics')`, which immediately unmounts the Overview tab and starts rendering Analytics. The heavy chart render blocks the main thread for 300ms. During this time, the user sees a blank panel — the old tab is gone, the new tab isn't ready.
Wrap the tab switch in `startTransition(() => setActiveTab('analytics'))`. React keeps showing the Overview tab (marked with `isPending` for a subtle opacity/spinner indicator) while rendering Analytics in the background. When ready, it swaps them in a single frame — no blank state.
Takeaway: useTransition is perfect for tab switching, accordion expansions, and any UI where you want the old content to stay visible while new content prepares. The `isPending` boolean lets you show a subtle loading indicator without destroying the current view.
A search results component receives `query` as a prop and does heavy filtering inline. You want to defer the results rendering but can't wrap the parent's setState in startTransition because you don't control the parent.
The parent component calls `setQuery(e.target.value)` directly. You can't add startTransition because you don't own the parent component (maybe it's from a library). Your heavy ResultsList re-renders on every keystroke because `query` prop changes immediately.
Use `useDeferredValue(query)` in ResultsList: `const deferredQuery = useDeferredValue(query)`. Filter using `deferredQuery` instead of `query`. React returns the old value during heavy renders, showing stale-but-fast results while computing the new filter in the background. Compare `query !== deferredQuery` to show a loading indicator.
Takeaway: useDeferredValue is the consumer-side equivalent of useTransition. Use useTransition when you control the state update (can wrap setState). Use useDeferredValue when you want to defer derived rendering from a prop you don't control.