Cuándo (casi nunca) usar createMutable: interop OOP y migración desde MobX
El mapa de los pocos contextos donde createMutable es la elección defendible: interop con librerías orientadas a objetos que mutan, migración incremental desde MobX o Vue sin reescribir todo de golpe, y estado local encapsulado que nunca fuga el proxy. La disciplina que lo vuelve seguro —encapsular y no filtrar— y las alternativas más seguras para todo lo demás: createStore, o createStore con produce.
Los tres contextos defendibles
El primero es la interoperabilidad con código que muta: un motor de física o de juego, una librería de canvas, un binding de formularios de terceros, cualquier API cuyo contrato sea escribir sobre un objeto que le entregas. Aquí el mutable no es una comodidad, es el único puente que no obliga a reescribir la librería. El segundo es la migración incremental desde un sistema de observables mutables —MobX, Vue— donde reescribir todo el estado al modelo canalizado de golpe sería inviable; el mutable te deja portar módulo a módulo. El tercero es el estado local y encapsulado: una lógica imperativa autocontenida —una máquina de estados, un acumulador complejo— cuyo proxy nunca abandona su módulo.
import { createMutable } from "solid-js/store";// Contexto 3: encapsulado. El proxy vive y muere dentro de esta funcion.function crearReproductor() { const s = createMutable({ tiempo: 0, reproduciendo: false }); // Se expone una superficie controlada, NO el proxy crudo return { get tiempo() { return s.tiempo; }, get reproduciendo() { return s.reproduciendo; }, play() { s.reproduciendo = true; }, pause() { s.reproduciendo = false; }, avanzar(dt: number) { s.tiempo += dt; }, };}Fíjate en lo que hace seguro al tercer caso: el proxy s nunca sale. Lo que se devuelve es una fachada de getters de lectura y métodos de escritura con nombre. Has reconstruido, a mano y en pequeño, el contrato explícito que createMutable disuelve —y esa es precisamente la disciplina que lo vuelve tolerable.
Migrar desde MobX sin reescribir todo
MobX y createMutable comparten modelo mental —estado mutable observable, derivaciones automáticas— lo que hace la traducción casi mecánica. Un makeAutoObservable se vuelve un createMutable; los computed se vuelven getters; las acciones se vuelven métodos que mutan this. La afinidad es tan alta que puedes migrar clase por clase manteniendo el resto de la app funcionando.
// Antes (MobX)// class Tienda {// items = [];// get total() { return this.items.reduce((s, i) => s + i.precio, 0); }// anadir(i) { this.items.push(i); }// }// makeAutoObservable(new Tienda());// Despues (Solid, createMutable): traduccion casi 1 a 1const tienda = createMutable({ items: [] as { precio: number }[], get total() { return this.items.reduce((s, i) => s + i.precio, 0); }, anadir(i: { precio: number }) { this.items.push(i); },});El valor de createMutable en la migración es táctico, no estratégico: es un puente para no bloquear el proyecto, no el destino. Una vez portada la app, el consejo del equipo sigue vigente —evaluar si ese estado gana claridad convertido a createStore—. Pero un puente que te deja cruzar sin demoler la orilla vale su peso, y aquí la afinidad de modelos lo convierte en el camino de menor resistencia.
Las alternativas más seguras
Para casi todo lo demás, la respuesta es createStore. Te da la misma reactividad de grano fino y el mismo envoltorio profundo, pero canaliza la escritura por setStore, devolviéndote el censo de mutaciones y el flujo explícito. Y si lo que te atraía del mutable era escribir como si mutaras, no necesitas renunciar a eso: setStore acepta produce, que te da un borrador mutable dentro de una función controlada, con la escritura imperativa por dentro y el contrato explícito por fuera.
import { createStore, produce } from "solid-js/store";const [store, setStore] = createStore({ items: [] as string[], contador: 0 });// Ergonomia imperativa DENTRO, escritura canalizada FUERAsetStore(produce((s) => { s.items.push("a"); // se lee y escribe como un mutable s.contador++; // pero todo ocurre dentro de setStore}));Este patrón —que la lección 5 desarrolla a fondo— es la síntesis que casi siempre buscabas: la comodidad de createMutable en el punto de escritura, sin perder la localizabilidad que da tener un setStore como ancla. Antes de alcanzar el mutable, pregúntate si produce no te da ya el 90% de lo que querías sin ninguno de los peligros.