Estoy migrando mi código base a svelte. Mi lógica empresarial contiene muchas clases, que dependen unas de otras. Creé un REPL para visualizar mi problema: Link .
En este ejemplo, el atributo de dinero de una persona solo se actualiza correctamente en la interfaz de usuario si se cambia directamente como una función html en línea (botón izquierdo). Al llamar a un método de clase (botón derecho), el estado de la clase se actualiza, la interfaz de usuario no.
Soy consciente de que este comportamiento es intencionado y que se deben usar escrituras para lograr reactividad fuera de los componentes esbeltos. ¿Es posible de alguna manera lograr reactividad usando clases como en REPL? ¿Necesito reemplazar sus atributos con escrituras para arreglar mi REPL? ¿Si es así, cómo?
<div id="app"> {#each teams as team} <div> {#each team.people as person} <li class="person-row"> <div>{person.name}</div> <div>{person.money}€</div> <button on:click={() => (person.money += 1)}>Add 1€ </button> <button on:click={() => person.addMoney(1)}>Add 1€ </button> </li> {/each} </div> {/each} </div> <script> class Person { constructor(name, money) { this.name = name; this.money = money; } addMoney(x) { this.money += x; } } class Team { constructor(name, people) { this.name = name; this.people = people; } } const p1 = new Person("Person 1", 1000); const p2 = new Person("Person 2", 2); const p3 = new Person("Person 3", 60); const p4 = new Person("Person 4", 15); const t1 = new Team("Team 1", [p1, p2]); const t2 = new Team("Team 2", [p3, p4]); const teams = [t1, t2]; </script> <style> .person-row { display: flex; flex-direction: row; } .person-row * { width: 100px; } </style>Una posible solución podría ser reasignar la propiedad a sí misma, así:
<button on:click={() => { person.addMoney(1); person.money = person.money; }} o si prefiere evitar una reasignación explícita, también puede devolver la propiedad de money desde el método addMoney()
addMoney(x) { this.money += x; return this.money; }por lo que el botón podría ser
<button on:click={() => { person.money = person.addMoney(1); }}Después de llamar a un método que muta un objeto (o matriz), agregue una declaración de asignación:
person.addMoney(1); person = person
Este es el método recomendado y permite que Svelte solo reaccione a los cambios dentro de ese objeto de persona. (Reescribir la aplicación utilizando datos sin procesar y mutación directa podría ser más adecuado para Svelte que migrar clases)
Otra otra opción es utilizar las tiendas. Actualmente, el uso de la notación $store solo funciona en el nivel superior. (Lo cual es útil para suscribirse y darse de baja automáticamente)
Su configuración con equipos y personas hace que sea difícil crear una configuración limpia con las tiendas integradas.
Pero el contrato de la tienda es flexible y potente y permite usar otros sistemas de reactividad, como RxJS, Redux y Vue:
import { readable} from "svelte/store" import { reactive as vueReactive, watch } from 'vue' function reactive(obj, options) { const ref = vueReactive(obj) return readable(ref, (set) => { return watch(ref, (prev, next) => { set(ref) }, options); }) } const teams = reactive([t1, t2]); {#each $teams as team}Como se muestra en este REPL
El uso de este enfoque tiene una penalización de rendimiento, ya que la tienda de los teams se actualiza con cada addMoney, lo que provoca muchas más verificaciones de invalidación por parte de Svelte.
Es un paso intermedio útil durante la migración.