Qu’est-ce que SolidJS ?
SolidJS est une bibliothèque d’interface utilisateur déclarative qui ressemble à React mais fonctionne de manière très différente. Elle utilise JSX et des composants, pourtant elle n’a pas de DOM virtuel et ne procède pas à des re-rendus. À la place, elle utilise une réactivité fine (fine-grained reactivity) : les signaux suivent qui les lit, et lorsqu’une valeur change, seuls les calculs et les nœuds du DOM qui en dépendent sont mis à jour.
L’effet concret est qu’une fonction de composant Solid ne s’exécute qu’une seule fois. Tout ce qui est réactif à l’intérieur est configuré lors de cette exécution, puis mis à jour de manière chirurgicale. Une fois ce concept assimilé, les performances de Solid et ses règles deviennent logiques.
Signals
Un signal est une valeur réactive créée avec createSignal. Il retourne un getter et un setter.
// Counter.jsx
import { createSignal } from "solid-js";
export function Counter() {
const [count, setCount] = createSignal(0);
return (
<button onClick={() => setCount((c) => c + 1)}>
Count: {count()}
</button>
);
}
Vous lisez un signal en l’appelant : count(). Cet appel est ce qui enregistre une dépendance. Passer une fonction au setter (setCount((c) => c + 1)) est la méthode sécurisée pour effectuer une mise à jour basée sur la valeur précédente.
Valeurs dérivées avec createMemo
createMemo calcule une valeur à partir d’autres signals et la met en cache. Elle est recalculée uniquement lorsqu’une dépendance change, et le résultat est partagé entre tous les lecteurs.
// cart.jsx
import { createSignal, createMemo } from "solid-js";
const [items, setItems] = createSignal([{ price: 10 }, { price: 20 }]);
const total = createMemo(() =>
items().reduce((sum, item) => sum + item.price, 0),
);
Pour des expressions simples en ligne, vous pouvez également utiliser une fonction classique, mais createMemo évite de répéter des opérations coûteuses. Utilisez-le lorsque le calcul est lourd ou lu à plusieurs endroits.
Effects
createEffect exécute un effet secondaire chaque fois que les signaux qu’il lit sont modifiés. Il sert à se synchroniser avec le monde extérieur, et non à calculer des valeurs.
// title.jsx
import { createEffect, createSignal } from "solid-js";
const [name, setName] = createSignal("Ada");
createEffect(() => {
document.title = `Hello, ${name()}`;
});
Les effects s’exécutent après le rendu et suivent automatiquement leurs dépendances. Utilisez onCleanup pour nettoyer les abonnements, les timers et les requêtes.
Les composants ne s’exécutent qu’une seule fois
C’est la règle qui piège souvent les développeurs React. Un composant Solid s’exécute une seule fois. Il s’agit d’une fonction de configuration qui crée des liaisons réactives, et non d’une fonction qui se réexécute à chaque changement d’état.
function Profile(props) {
// Do not destructure props — that breaks reactivity.
// Read them where you use them instead.
return <h1>{props.user.name}</h1>;
}
Comme les props sont des getters réactifs, lisez-les là où vous les utilisez (props.user.name) plutôt que de les déstructurer. Il en va de même pour les signals : appelez-les à l’intérieur du JSX ou à l’intérieur d’un memo, et non une seule fois en haut du composant.
Composants de flux de contrôle
Solid utilise des composants plutôt que des directives de template pour les conditionnels et les listes, ce qui permet de tout garder en JavaScript et laisse le compilateur optimiser les mises à jour.
// list.jsx
import { Show, For } from "solid-js";
<Show when={users().length > 0} fallback={<p>No users yet.</p>}>
<ul>
<For each={users()}>{(user) => <li>{user.name}</li>}</For>
</ul>
</Show>
Show affiche son contenu de secours (fallback) lorsque la condition est fausse, et For utilise des clés par référence pour les éléments afin de pouvoir déplacer les nœuds du DOM plutôt que de les recréer. Index est disponible lorsque vous souhaitez utiliser l’index comme clé.
Stores
Pour les objets réactifs imbriqués, createStore fournit un proxy avec des mises à jour basées sur le chemin.
// store.jsx
import { createStore } from "solid-js/store";
const [user, setUser] = createStore({
name: "Ada",
address: { city: "London" },
});
setUser("address", "city", "Paris");
Seules les parties de l’arbre qui ont été modifiées notifient leurs dépendants ; ainsi, la mise à jour d’une propriété profonde n’invalide pas les lectures non liées. Les Stores sont la méthode recommandée pour gérer un état structuré.
Ressources et données asynchrones
createResource enveloppe une fonction asynchrone dans un signal, vous offrant ainsi des états de chargement et d’erreur sans gestion manuelle.
// user.jsx
import { createResource, Show } from "solid-js";
const [user] = createResource(() => fetch("/api/user").then((r) => r.json()));
<Show when={user()} fallback={<p>Loading…</p>}>
<h1>{user().name}</h1>
</Show>;
La ressource s’exécute à nouveau lorsque son signal source change et annule le travail obsolète, ce qui en fait une solution idéale pour les données dépendant de paramètres de route ou de saisies utilisateur.
Routage et SolidStart
Solid Router gère la navigation côté client, et SolidStart est le méta-framework qui ajoute le routage basé sur les fichiers, le rendu serveur et le chargement de données — l’équivalent de Next.js pour React ou SvelteKit pour Svelte. Pour tout projet dépassant le stade d’un simple widget, commencez par SolidStart.
Bonnes pratiques
- Lisez les signals et les props là où vous les utilisez ; ne les déstructurez jamais.
- Utilisez
createMemopour les valeurs dérivées coûteuses ou largement partagées. - Utilisez
createEffectuniquement pour les effets de bord, et nettoyez-les aveconCleanup. - Privilégiez
createStorepour les états imbriqués. - Utilisez
ShowetForau lieu de conditionnels manuels et de.map. - Considérez vos composants comme des fonctions de configuration et évitez de compter sur leur réexécution.
- Tournez-vous vers
createResourcepour les données asynchrones liées à des sources réactives.
Erreurs courantes
- Déstructurer les props ou les valeurs de signal, ce qui brise la réactivité.
- S’attendre à ce que le corps du composant s’exécute à nouveau après un changement d’état.
- Utiliser un effet pour calculer une valeur au lieu d’un memo.
- Oublier
onCleanup, entraînant des fuites de souscriptions ou de timers. - Utiliser
.mapdans le JSX au lieu deFor, perdant ainsi les mises à jour basées sur les clés. - Supposer que les règles de React s’appliquent et tenter d’utiliser des hooks qui n’existent pas.
Et après ?
Solid privilégie la compréhension à la mémorisation. Comparez son modèle avec ceux de React, Vue et Svelte, perfectionnez vos connaissances en JavaScript et TypeScript, et appuyez-vous sur Vite pour le build. Ensuite, créez une petite application réactive et observez la faible proportion de code qui est réexécutée.