React 19.2 : Activity Component et useEffectEvent Révolutionnent le Développement
Salut HaWkers, React continue d'évoluer et la version 19.2, lancée en octobre 2025, apporte deux nouveautés qui promettent de changer la façon dont nous construisons des applications : le Activity component et le hook useEffectEvent. Ces ajouts résolvent des problèmes que les développeurs affrontent depuis des années.
Avez-vous déjà eu des difficultés à gérer le préchargement de contenu ou vous êtes-vous frustré avec les complexités du tableau de dépendances de useEffect ? Alors cet article est pour vous.
Ce Qui est Nouveau dans React 19.2
C'est la troisième release significative de l'année, suivant React 19 en décembre 2024 et React 19.1 en juin 2025. L'équipe React s'est concentrée sur deux problèmes fondamentaux de l'expérience développeur.
Activity Component : L'Avenir du Pre-Rendering
Le nouveau composant <Activity /> permet de diviser votre application en "activités" qui peuvent être contrôlées et priorisées. C'est une alternative au rendu conditionnel traditionnel, offrant deux modes : visible et hidden.
Pourquoi Activity Est Révolutionnaire
Traditionnellement, quand vous devez rendre du contenu conditionnellement, vous utilisez quelque chose comme ceci :
// Approche traditionnelle - le composant est détruit et recréé
function Dashboard() {
const [activeTab, setActiveTab] = useState('overview');
return (
<div>
<nav>
<button onClick={() => setActiveTab('overview')}>Overview</button>
<button onClick={() => setActiveTab('analytics')}>Analytics</button>
<button onClick={() => setActiveTab('settings')}>Settings</button>
</nav>
{/* Chaque changement d'onglet détruit le composant précédent */}
{activeTab === 'overview' && <OverviewPanel />}
{activeTab === 'analytics' && <AnalyticsPanel />}
{activeTab === 'settings' && <SettingsPanel />}
</div>
);
}Le problème avec cette approche est que chaque changement d'onglet détruit le composant précédent et en crée un nouveau, perdant tout l'état interne et exigeant de nouvelles requêtes de données.
La Solution avec Activity
Avec le Activity component, vous pouvez maintenir les composants montés mais cachés :
import { Activity } from 'react';
function Dashboard() {
const [activeTab, setActiveTab] = useState('overview');
return (
<div>
<nav>
<button onClick={() => setActiveTab('overview')}>Overview</button>
<button onClick={() => setActiveTab('analytics')}>Analytics</button>
<button onClick={() => setActiveTab('settings')}>Settings</button>
</nav>
{/* Les composants restent montés, seule la visibilité change */}
<Activity mode={activeTab === 'overview' ? 'visible' : 'hidden'}>
<OverviewPanel />
</Activity>
<Activity mode={activeTab === 'analytics' ? 'visible' : 'hidden'}>
<AnalyticsPanel />
</Activity>
<Activity mode={activeTab === 'settings' ? 'visible' : 'hidden'}>
<SettingsPanel />
</Activity>
</div>
);
}
Avantages du Activity Component
1. Préservation de l'État
Les inputs remplis, la position de scroll et l'état interne sont maintenus quand vous naviguez entre les activities.
2. Pre-fetching Intelligent
Vous pouvez rendre des parties cachées de l'application que l'utilisateur accèdera probablement :
function ProductPage({ productId }) {
const [showReviews, setShowReviews] = useState(false);
return (
<div>
<ProductDetails id={productId} />
<button onClick={() => setShowReviews(true)}>
Voir les Avis
</button>
{/* Les avis sont chargés en arrière-plan */}
<Activity mode={showReviews ? 'visible' : 'hidden'}>
<ReviewsSection productId={productId} />
</Activity>
</div>
);
}3. Navigation Instantanée
Les navigations arrière deviennent instantanées car l'état précédent existe toujours en mémoire.
useEffectEvent : Adieu Dependency Hell
Le hook useEffectEvent résout l'un des plus grands maux de tête de React : gérer les dépendances de useEffect quand vous avez besoin de valeurs à jour sans re-exécuter l'effet.
Le Problème Classique
Considérez ce scénario courant :
// Problème : analytics se déclenche plusieurs fois inutilement
function ProductPage({ productId, category, user }) {
useEffect(() => {
// Nous voulons logger seulement quand productId change
// Mais nous avons besoin de category et user.id pour le log
analytics.logProductView({
productId,
category,
userId: user.id,
timestamp: Date.now()
});
}, [productId, category, user.id]); // Problème : se déclenche si category ou user change
return <ProductDetails id={productId} />;
}
Solutions Anciennes (Problématiques)
Les développeurs utilisaient des ref pour contourner cela :
// Solution ancienne avec refs - fonctionne mais verbeuse
function ProductPage({ productId, category, user }) {
const categoryRef = useRef(category);
const userRef = useRef(user);
useLayoutEffect(() => {
categoryRef.current = category;
userRef.current = user;
});
useEffect(() => {
analytics.logProductView({
productId,
category: categoryRef.current,
userId: userRef.current.id,
timestamp: Date.now()
});
}, [productId]);
return <ProductDetails id={productId} />;
}La Solution avec useEffectEvent
Le nouveau hook rend cela élégant et déclaratif :
import { useEffect, useEffectEvent } from 'react';
function ProductPage({ productId, category, user }) {
// Crée une fonction stable qui accède toujours aux valeurs actualisées
const logProductView = useEffectEvent(() => {
analytics.logProductView({
productId,
category, // Toujours la valeur la plus récente
userId: user.id, // Toujours la valeur la plus récente
timestamp: Date.now()
});
});
useEffect(() => {
// logProductView n'a pas besoin d'être dans les dépendances
// mais utilise toujours les valeurs les plus récentes des props
logProductView();
}, [productId]); // Se déclenche seulement quand productId change
return <ProductDetails id={productId} />;
}Cas d'Usage Pratiques de useEffectEvent
1. Event Handlers dans les Effects
function ChatRoom({ roomId, onMessage }) {
// onMessage peut changer, mais nous ne voulons pas reconnecter
const handleMessage = useEffectEvent((message) => {
onMessage(message);
});
useEffect(() => {
const connection = createConnection(roomId);
connection.on('message', handleMessage);
connection.connect();
return () => connection.disconnect();
}, [roomId]); // Reconnecte seulement quand roomId change
}
2. Logging et Analytics
function SearchResults({ query, filters, results }) {
const logSearch = useEffectEvent(() => {
analytics.logSearch({
query,
filterCount: Object.keys(filters).length,
resultCount: results.length,
timestamp: Date.now()
});
});
useEffect(() => {
// Logue seulement quand query change
// mais inclut les données actualisées de filters et results
logSearch();
}, [query]);
return <ResultsList results={results} />;
}3. Synchronisation avec des APIs Externes
function VideoPlayer({ videoId, volume, playbackRate }) {
const updatePlayerSettings = useEffectEvent(() => {
// Configurations qui ne doivent pas causer le rechargement de la vidéo
player.setVolume(volume);
player.setPlaybackRate(playbackRate);
});
useEffect(() => {
const player = createPlayer(videoId);
// Applique les configurations initiales
updatePlayerSettings();
return () => player.destroy();
}, [videoId]); // Recharge la vidéo seulement quand videoId change
// Met à jour les configurations sans recharger
useEffect(() => {
updatePlayerSettings();
}, [volume, playbackRate]);
}React Performance Tracks dans DevTools
React 19.2 ajoute aussi de nouvelles tracks de performance dans Chrome DevTools qui facilitent beaucoup le debugging.
Scheduler Track
Montre ce que React traite à différentes priorités :
function App() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const handleSearch = (term) => {
// Priorité haute - mise à jour immédiate de l'input
setSearchTerm(term);
// Priorité basse - la recherche ne bloque pas l'UI
startTransition(() => {
const filtered = performExpensiveSearch(term);
setResults(filtered);
});
};
return (
<div>
<input
value={searchTerm}
onChange={(e) => handleSearch(e.target.value)}
/>
<SearchResults results={results} />
</div>
);
}Dans DevTools, vous verrez des tracks séparées pour :
- Blocking : Interactions utilisateur (haute priorité)
- Transition : Updates dans startTransition
- Idle : Travail de basse priorité
Migration et Compatibilité
Mise à Jour vers React 19.2
La mise à jour est simple et n'a pas de breaking changes par rapport à React 19.1 :
# npm
npm install react@19.2.0 react-dom@19.2.0
# yarn
yarn add react@19.2.0 react-dom@19.2.0
# pnpm
pnpm add react@19.2.0 react-dom@19.2.0Compatibilité des Types TypeScript
Pour TypeScript, assurez-vous de mettre à jour les types :
npm install @types/react@19.2.0 @types/react-dom@19.2.0Les nouveaux types incluent des définitions complètes pour Activity et useEffectEvent :
import { Activity, useEffectEvent } from 'react';
interface ActivityProps {
mode: 'visible' | 'hidden';
children: React.ReactNode;
}
// useEffectEvent préserve le type de la fonction
const handler = useEffectEvent((event: MouseEvent) => {
// event est correctement typé
console.log(event.clientX, event.clientY);
});Comparaison avec les Approches Précédentes
Activity vs CSS display: none
| Aspect | Activity hidden | CSS display: none |
|---|---|---|
| React Lifecycle | Pausé | Continue d'exécuter |
| Mémoire | Optimisée | État maintenu |
| Effects | N'exécutent pas | Continuent d'exécuter |
| Re-render | Ne se produit pas | Peut se produire |
useEffectEvent vs useCallback
| Aspect | useEffectEvent | useCallback |
|---|---|---|
| Valeurs | Toujours à jour | Périmées si deps changent |
| Dépendances | Jamais listé | Doit être listé |
| Cas d'usage | Effects | Props de composants |
| Stabilité | Toujours stable | Dépend des deps |
Conclusion
React 19.2 représente un pas important supplémentaire dans l'évolution du framework. L'Activity component résout élégamment le problème du préchargement et de la préservation d'état, tandis que useEffectEvent élimine des années de frustration avec les dependency arrays.
Ces nouveaux outils ne sont pas juste des améliorations incrémentales - ils changent fondamentalement la façon dont nous pensons à la gestion d'état et aux effets secondaires dans les applications React.
Si vous travaillez avec React, je recommande de commencer à expérimenter ces features dans des projets plus petits pour comprendre leur potentiel. Pour compléter vos connaissances sur la performance, consultez notre article sur ECMAScript 2025 et les Nouvelles Features du JavaScript.

