Nous avons construit la même application en SolidJS et React : Signals vs Hooks
Le trimestre dernier, nous avons eu un projet client qui nous a donné la parfaite excuse pour faire quelque chose que nous brûlions d'envie d'essayer : construire la même application dans SolidJS et React, puis tout comparer. Pas une todo app. Pas un compteur. Un vrai dashboard de production avec authentification, mises à jour de données en temps réel, formulaires complexes et un module de graphique qui rend des milliers de points de données.
Les résultats nous ont surpris. Pas parce qu'un framework a "gagné" -- mais parce que les compromis étaient bien plus nuancés que le discours sur Twitter le suggère. Certaines choses nous les attendions. D'autres nous ont complètement pris de court. Voici ce que nous avons réellement appris.
Table des matières
- L'application que nous avons construite
- Signals vs Hooks : un changement de modèle mental
- Comparaison de la taille des bundles
- Benchmarks de performance de rendu
- Expérience développeur et écosystème
- Compromis de production qui comptent réellement
- Quand choisir SolidJS plutôt que React
- Comparaison de code : modèles réels
- FAQ

L'application que nous avons construite
L'application est un dashboard d'analytique en temps réel pour un client e-commerce. Voici ce qu'elle comprend :
- Flux d'authentification avec tokens JWT et logique de rafraîchissement
- Dashboard avec 6 panneaux de widgets, chacun récupérant des données depuis différents endpoints API
- Flux de commandes en temps réel utilisant des connexions WebSocket
- Graphiques interactifs rendant 5 000+ points de données (en utilisant une librairie de graphique)
- Formulaires filtrés complexes avec dropdowns dépendants et sélecteurs de plage de dates
- Panneau de paramètres administrateur avec gestion d'état imbriquée
- Disposition responsive avec navigation sidebar
Les deux versions se connectent à la même API backend. Les deux utilisent TypeScript. Les deux utilisent Vite comme outil de build. Nous avons gardé les dépendances tierces aussi similaires que possible -- même librairie de graphique (Chart.js), même client HTTP (ky), même wrapper WebSocket.
La version React utilise React 19 avec des hooks. La version SolidJS utilise Solid 1.9. Nous n'avons pas utilisé de meta-frameworks (pas de Next.js, pas de SolidStart) parce que nous voulions isoler les différences de framework sans que le routing et SSR brouillent la comparaison.
Signals vs Hooks : un changement de modèle mental
C'est la grande. Et honnêtement, il a fallu environ une semaine à notre équipe pour arrêter d'écrire du code en forme React dans SolidJS.
Comment fonctionnent les React Hooks
Vous savez cela, mais c'est worth stating explicitement pour la comparaison. Le modèle de React est : quand l'état change, la fonction du composant se réexécute. Toute la fonction. Chaque useState, chaque useMemo, chaque useCallback -- ce sont tous des mécanismes pour contourner le fait que la fonction entière se relance.
// React: Cette fonction entière se réexécute à chaque changement d'état
function OrderFeed() {
const [orders, setOrders] = useState([]);
const [filter, setFilter] = useState('all');
// Ceci recalcule à chaque rendu sauf si nous mémoïzons
const filteredOrders = useMemo(() =>
orders.filter(o => filter === 'all' || o.status === filter),
[orders, filter]
);
// Cette ref se recrée conceptuellement à chaque rendu
const handleNewOrder = useCallback((order) => {
setOrders(prev => [order, ...prev]);
}, []);
useEffect(() => {
const ws = connectWebSocket(handleNewOrder);
return () => ws.close();
}, [handleNewOrder]);
return <OrderList orders={filteredOrders} />;
}
Comment fonctionnent les Solid Signals
Le modèle de Solid est fondamentalement différent. La fonction du composant s'exécute une fois. Après cela, seules les expressions spécifiques qui lisent un signal se réexécutent quand ce signal change. Il n'y a pas de virtual DOM diff. Il n'y a pas de reconciliation. Le graphe réactif trace exactement quels nœuds DOM dépendent de quels signals.
// Solid: Cette fonction s'exécute UNE FOIS
function OrderFeed() {
const [orders, setOrders] = createSignal([]);
const [filter, setFilter] = createSignal('all');
// Ceci est automatiquement tracé -- pas besoin de tableau de dépendances
const filteredOrders = createMemo(() =>
orders().filter(o => filter() === 'all' || o.status === filter())
);
// Pas de useCallback nécessaire -- cette closure est stable
const handleNewOrder = (order) => {
setOrders(prev => [order, ...prev]);
};
// onMount au lieu de useEffect avec deps vides
onMount(() => {
const ws = connectWebSocket(handleNewOrder);
onCleanup(() => ws.close());
});
return <OrderList orders={filteredOrders()} />;
}
Ce que cela signifie en pratique
La version Solid n'a pas de tableaux de dépendances. Pas de useCallback. Pas de useMemo pour l'état dérivé (bien que createMemo existe pour les calculs coûteux -- la différence est que c'est opt-in pour la performance, pas requis pour la correction).
Voici ce qui nous a vraiment mordus pendant le développement :
Destructurer les props supprime la réactivité dans Solid. Nous avions un junior dev destructurer les props dans un composant Solid et avons passé 45 minutes à déboguer pourquoi les updates ne se propageaient pas. Dans React, la destructuration est fine parce que la fonction entière se relance. Dans Solid, vous devez accéder à
props.valueà l'intérieur du JSX ou d'une portée tracée.Les early returns sont délicats dans Solid. Vous ne pouvez pas faire
if (!data()) return <Loading />en haut d'un composant Solid comme vous le feriez dans React. La fonction du composant ne s'exécute qu'une fois, donc ce conditionnel ne se réévaluerait jamais. Vous devez utiliser<Show when={data()}>à la place.Pas de bugs de closure stale. C'était la grande victoire. Dans notre version React, nous avions trois bugs de closure stale distincts la première semaine liés aux handlers WebSocket capturant l'ancien état. La version Solid en avait zéro, parce que les signals sont toujours lus au moment de l'accès, pas capturés dans une closure.
Comparaison de la taille des bundles
Nous avons mesuré les deux builds de production avec exactement la même configuration Vite, compression gzip et stratégie de code splitting.
| Métrique | React 19 | SolidJS 1.9 | Différence |
|---|---|---|---|
| Runtime du framework | 44.2 KB (gzip) | 7.1 KB (gzip) | -84% |
| Bundle initial total | 127.8 KB | 89.3 KB | -30% |
| App totale (tous les chunks) | 312.4 KB | 274.1 KB | -12% |
| Premier chunk (chemin critique) | 68.4 KB | 41.2 KB | -40% |
| Nombre de chunks | 14 | 14 | Même |
Le runtime de Solid est dramatiquement plus petit. Ce n'est pas une nouvelle -- Ryan Carniato en a parlé longuement. Mais ce qui nous a surpris, c'est que la différence de taille totale de l'app s'est considérablement réduite une fois que vous ajoutez du code d'application réel, des librairies tierces et des assets.
Le runtime du framework compte surtout pour la charge initiale. Et à 7.1 KB gzippé, Solid disparait essentiellement dans le bruit. Les 44 KB de React sont notables, surtout sur les connexions mobiles.
Tree Shaking
Solid fait du tree shaking mieux que React. Les primitives Solid inutilisées sont éliminées complètement. Avec React, le reconciler et l'architecture fibre se livrent que vous utilisiez toutes leurs fonctionnalités ou non. Nous avons confirmé ceci en construisant une page minimale dans les deux -- le plancher de Solid est plus bas.

Benchmarks de performance de rendu
Nous avons exécuté des benchmarks structurés en utilisant les profils de performance Chrome DevTools, Lighthouse et l'instrumentation de temps personnalisée. Tous les tests sur un MacBook Pro M2 avec ralentissement CPU défini à 4x pour simuler des appareils mid-range.
Rendu de graphique (5 000 points de données)
| Métrique | React 19 | SolidJS 1.9 |
|---|---|---|
| Rendu initial | 142ms | 89ms |
| Re-rendu lors du changement de filtre | 67ms | 23ms |
| Mémoire pendant le rendu | 18.4 MB | 11.2 MB |
| Nœuds DOM créés | 5,847 | 5,812 |
Solid était constamment plus rapide sur les re-rendus parce qu'il ne fait pas de diff d'arbre virtual DOM. Quand un filtre signal change, seules les expressions qui lisent ce signal se mettent à jour. Les améliorations du compilateur React 19 ont aidé -- le même test sur React 18 était 95ms pour les re-rendus -- mais Solid avait toujours un avantage clair.
Flux de commandes en temps réel (100 mises à jour/seconde)
C'est où les choses sont devenues vraiment intéressantes. Nous avons poussé 100 messages WebSocket par seconde dans le flux de commandes.
| Métrique | React 19 | SolidJS 1.9 |
|---|---|---|
| Drops de frame (par 10s) | 12 | 2 |
| Temps de paint moyen | 8.3ms | 3.1ms |
| Temps de paint max | 34ms | 11ms |
| Utilisation CPU (moy) | 24% | 9% |
Solid a absolument écrasé ce benchmark. Les mises à jour haute fréquence sont où la réactivité fine-grained paie les plus gros dividendes. React faisait du batching des updates (ce qui est bien), mais faisait quand même diff plus de DOM que nécessaire à chaque batch.
Nous devrions noter : les useTransition et batching automatique de React 19 ont rendu ceci beaucoup mieux que React 18 ne l'aurait été. Et pour la plupart des apps du monde réel, vous ne poussez pas 100 mises à jour par seconde. À 10 mises à jour/seconde, les deux frameworks étaient lisses.
Formulaire complexe avec 40 champs
| Métrique | React 19 | SolidJS 1.9 |
|---|---|---|
| Lag de saisie au clavier | 2-4ms | <1ms |
| Rendu de soumission de formulaire | 28ms | 12ms |
| Re-rendus de composant par touche | 3-8 | 1 |
Dans React, taper dans un champ causerait le re-rendu des composants parents à moins que nous mémoïzions soigneusement tout. Dans Solid, taper dans un champ met à jour littéralement seulement le nœud de texte DOM de ce champ. Rien d'autre ne se réexécute.
Expérience développeur et écosystème
La performance n'est pas tout. Vous devez réellement construire la chose, la déboguer, embaucher pour elle et la maintenir.
Taille de l'écosystème (au début de 2025)
| Facteur | React | SolidJS |
|---|---|---|
| Téléchargements npm par semaine | ~28M | ~85K |
| Stars GitHub | 233K+ | 33K+ |
| Questions Stack Overflow | 470K+ | ~2K |
| Librairies de composants UI | 50+ options matures | 5-8 options |
| Offres d'emploi (LinkedIn US) | ~45 000 | ~200 |
| Meta-framework | Next.js (mature) | SolidStart (beta) |
C'est l'éléphant dans la salle. L'écosystème de React est des ordres de grandeur plus grand. Quand nous avons eu besoin d'un sélecteur de plage de dates pour Solid, nous avons dû soit porter un React ou écrire le nôtre. Dans React, nous avions 15 options parmi lesquelles choisir.
Nous avons utilisé Kobalte pour les primitives UI accessibles dans Solid, et c'est vraiment bon. Mais ce n'est pas Radix UI en termes de couverture de composants.
Débogage
React DevTools est mature, bien entretenu et quelque chose que chaque frontend dev connaît. Solid a sa propre extension DevTools, et c'est décent -- vous pouvez inspecter le signal graph, ce qui est en fait plus utile pour tracker les bugs de réactivité que la vue d'arbre de composants de React. Mais c'est moins poli.
Support TypeScript
Les deux sont excellents. Le support TypeScript de Solid est en fait légèrement meilleur pour JSX parce que le compilateur gère plus au moment de la build. Nous avions moins de gymnastics de types dans la codebase Solid.
Compromis de production qui comptent réellement
Après avoir construit les deux versions et déployé la version Solid en staging (le client a finalement choisi React pour la production -- plus sur cela ci-dessous), voici les compromis qui comptaient réellement :
Embauche
Notre client a une équipe de 8 frontend developers. Tous connaissent React. Aucun n'avait utilisé Solid. Temps d'entraînement estimé : 2-3 semaines pour la compétence, 2-3 mois pour la maîtrise. C'est un vrai coût. C'est le facteur single biggest dans la plupart des décisions de production, et c'est pourquoi nous recommandons généralement React ou des frameworks comme Next.js pour les équipes qui ont besoin d'embaucher fréquemment.
Compatibilité des librairies tierces
Nous avons dû écrire des wrappers personnalisés pour trois librairies qui avaient des intégrations spécifiques à React. Ceci a ajouté approximativement 20 heures de temps de développement. Dans un projet React, ces heures n'existent pas.
Server-Side Rendering
SolidStart est prometteur mais était toujours en beta pendant notre projet. Next.js est battle-tested. Pour les projets où nous avons besoin d'une SSR de niveau production avec tous les détails, nous continuons à nous tourner vers Next.js development ou Astro selon le modèle de contenu.
Performance où elle compte
Voici la vérité honnête : pour ce dashboard particulier, les deux frameworks ont performé assez bien pour la production. La version Solid était mesurément plus rapide, mais la version React n'était jamais lente. Les utilisateurs ne remarqueraient pas la différence dans la plupart des interactions.
L'exception était le flux en temps réel à haute fréquence d'updates. Si votre app a un cas d'usage comme celui-là, l'avantage de performance de Solid est significatif, pas juste du bragging de benchmark.
Quand choisir SolidJS plutôt que React
Après cette expérience, voici notre framework honnête pour la décision :
Choisir SolidJS quand :
- Votre app a des updates réactives haute fréquence (dashboards, trading platforms, collaboration en temps réel)
- La taille du bundle est critique (embedded widgets, micro-frontends, mobile-first)
- Votre équipe est petite et prête à investir dans l'apprentissage d'un nouveau paradigme
- Vous voulez une réactivité fine-grained sans combattre le framework
- Vous construisez quelque chose de nouveau et n'avez pas besoin d'un écosystème massif de librairies de composants
Choisir React quand :
- Votre équipe connaît déjà React (cela seul est généralement décisif)
- Vous avez besoin d'un meta-framework mature (Next.js, Remix)
- La disponibilité de librairies tierces est importante
- Vous embauchez et avez besoin d'un large bassin de talents
- Les exigences de performance de votre app sont typiques (pas extrêmes)
Pour nos projets headless CMS development, React domine toujours parce que les intégrations CMS (Sanity, Contentful, Storyblok) ont des SDKs React de première classe. Le support de Solid existe mais est souvent maintenu par la communauté.
Comparaison de code : modèles réels
Regardons certains modèles réels du projet côte à côte.
Data Fetching avec Loading States
React :
function Dashboard() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchDashboardData()
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, []);
if (loading) return <Skeleton />;
if (error) return <ErrorBanner error={error} />;
return <DashboardGrid data={data} />;
}
SolidJS :
function Dashboard() {
const [data] = createResource(fetchDashboardData);
return (
<Suspense fallback={<Skeleton />}>
<ErrorBoundary fallback={(err) => <ErrorBanner error={err} />}>
<DashboardGrid data={data()} />
</ErrorBoundary>
</Suspense>
);
}
Le createResource de Solid avec Suspense est genuinely elegant. React a Suspense aussi (et c'est devenu mieux dans React 19), mais la version de Solid s'est sentie plus naturelle à utiliser. Moins de boilerplate, moins de variables d'état à gérer.
Conditional Rendering
React :
{user ? (
<Profile user={user} />
) : (
<LoginPrompt />
)}
SolidJS :
<Show when={user()} fallback={<LoginPrompt />}>
{(u) => <Profile user={u()} />}
</Show>
Le composant <Show> de Solid existe parce que les ternaires ne fonctionnent pas de la même façon quand la fonction du composant ne s'exécute qu'une fois. Il a fallu s'y habituer, mais le pattern callback vous donne une référence narrowed, non-null qui est nice pour TypeScript.
List Rendering
React :
{orders.map(order => (
<OrderRow key={order.id} order={order} />
))}
SolidJS :
<For each={orders()}>
{(order) => <OrderRow order={order} />}
</For>
Le <For> de Solid n'a pas besoin de keys parce qu'il trace les items du tableau par référence. Quand un item bouge dans le tableau, Solid bouge le nœud DOM réel. React démonterait et remonterait. C'est pourquoi la performance de liste de Solid est si bonne.
FAQ
SolidJS est-il production-ready en 2025 ?
Oui. Solid 1.x a été stable pendant plus de deux ans. Des entreprises comme Cloudflare et Samsung l'ont utilisé en production. La librairie core est mature et bien testée. L'écosystème autour (SolidStart, librairies de composants) est plus petit que celui de React mais grandit régulièrement. La question n'est pas si Solid est prêt -- c'est si votre équipe et les exigences du projet s'alignent avec sa taille d'écosystème.
Puis-je migrer de React à SolidJS progressivement ?
Pas facilement. Malgré la syntaxe JSX similaire, les modèles runtime sont fondamentalement différents. Vous ne pouvez pas intégrer les composants Solid dans une app React (ou vice versa) sans boundaries iframe ou web component. Une migration serait essentiellement une réécriture. Si vous l'envisagez, commencez avec une nouvelle feature isolée ou micro-frontend plutôt que d'essayer de convertir du code React existant.
SolidJS supporte-t-il le server-side rendering ?
Oui. SolidStart fournit SSR, streaming et server functions. C'est fonctionnel et s'améliore rapidement, mais au début de 2025, c'est toujours moins mature que Next.js ou Remix. Pour les projets SSR-heavy, nous recommanderions toujours d'évaluer Next.js ou Astro selon vos besoins de contenu.
Comment le compilateur de React 19 se compare-t-il à l'approche de Solid ?
Le compilateur de React 19 (anciennement React Forget) auto-mémoïze les composants pour réduire les re-rendus inutiles. C'est une amélioration significative. Mais il fonctionne toujours dans le modèle de React de réexécuter les fonctions de composants et de differ un virtual DOM. Solid saute les deux étapes entièrement. Le compilateur rend React plus rapide, mais ne change pas l'architecture fondamentale. Dans nos benchmarks, React 19 avec le compilateur était environ 30% plus rapide que React 18, mais toujours plus lent que Solid sur des scénarios update-heavy.
Que dire de Preact Signals comme compromis intermédiaire ?
Preact Signals (et l'adaptateur @preact/signals-react) apportent une réactivité type-signal à l'écosystème React. C'est une approche intéressante, mais elle combat le modèle core de React plutôt que de travailler avec. Nous l'avons testée brièvement et trouvé edge cases avec Suspense et concurrent features. Si vous voulez des signals, Solid vous donne l'expérience complète sans la discordance d'impédance.
SolidJS est-il plus difficile à apprendre que React ?
Si vous connaissez déjà React, l'API de Solid vous semblera familière -- JSX similaire, modèles similaires. La partie difficile est de désapprendre le modèle mental de React. Vous allez chercher les patterns useEffect qui n'existent pas. Vous allez destructurer les props et casser la réactivité. Vous allez essayer les early returns et vous demander pourquoi ils ne fonctionnent pas. Budgétez environ 1-2 semaines pour qu'un React dev expérimenté devienne productif dans Solid, et un autre mois ou deux pour arrêter d'écrire du Solid avec saveur React.
Quel framework a un meilleur support TypeScript ?
Les deux ont un excellent support TypeScript. Solid a un léger avantage parce que son compilateur peut fournir des types plus étroits dans certains patterns (comme la callback dans <Show>), et vous n'avez pas besoin du même volume de paramètres de type generic que certains React hooks complexes requièrent parfois. Mais honnêtement, les deux sont super. Ce ne devrait pas être un facteur décisif.
Devrais-je utiliser SolidJS pour mon prochain projet ?
Cela dépend de vos contraintes. Si vous êtes une petite équipe construisant quelque chose de sensible à la performance et que vous êtes prêt à investir dans la courbe d'apprentissage et à contourner un écosystème plus petit, Solid est un choix réellement excellent. Si vous avez besoin d'embaucher des React developers, d'utiliser des librairies de composants établies ou d'avoir un meta-framework battle-tested pour la production, React est le pari plus sûr. Il n'y a pas de réponse universelle -- seulement la bonne réponse pour votre situation spécifique. Si vous voulez discuter de la décision pour votre projet, contactez-nous et nous pouvons vous aider à évaluer les compromis.