Estoy haciendo un clon de Trello en Svelte usando tiendas personalizadas y derivadas. Esbeltos relojes de reactividad para la asignación , por lo que necesito reasignar mis almacenes de matriz, pero noté que las tiendas derivadas de matrices escribibles recalculan toda la matriz. Seguramente puedo tener más rendimiento aquí, especialmente si solo se actualiza un único valor de matriz.
// The store in question, edited for terseness const cards = writeable([]); // adding to the card somewhere in code cards.update((cards) => (cards = [...cards, card])); // the derived store, that loops through all cards (because of reduce) // this groups the card by its listId const cardsGroupedByList = derived(cards, ($cards) => { return $cards.reduce((list, card) => { console.log('recalculating cards'); const data = list.get(card.listId) || []; return list.set(card.listId, [...data, card]); }, new Map()); }); En la consola, cardsGroupedByList imprimirá n veces, pero Svelte solo muestra el componente correspondiente una vez, por lo que esto es puramente manipulación de datos. ¿Hay una mejor manera de hacer esto?
Aquí hay un Svelte REPL en funcionamiento con múltiples listas y tarjetas.
Una posible solución es tener 2 tiendas personalizadas. Solo se actualiza una vez, pero definitivamente pierde la elegancia de una tienda derivada.
// cards now need their set and add methods modified // otherwise I risk my group running out of sync export const cards = (() => { const { subscribe, set, update } = writable<Card[]>([]); return { subscribe, set: (cards: Card[]) => { cardsGroupedByList.set(cards); // set the group, reduce once set(cards); }, add: (card: Card) => { cardsGroupedByList.update(card); // add to the group update((cards) => (cards = [...cards, card])); }, }; })(); // groupBy becomes a custom store that retains internal state // run the risk of the group becoming out of sync with cards // could have issues when the card moves -- would need to add/remove or recalc export const cardsGroupedByList = (() => { const init = new Map(); const { subscribe, set, update } = writable(init); function groupBy(groups, card) { console.log('calculating groups'); // same console log, only happens once const data = groups.get(card.listId) || []; return groups.set(card.listId, [...data, card]); } return { subscribe, set: (cards: Card[]) => set(cards.reduce(groupBy, init)), update: (card) => { update((groups) => groupBy(groups, card)); }, }; })();En su caso de uso específico, no necesita crear una tienda adicional y simplemente puede reducir en el script de la aplicación :)
App.esbelta
<script> import { cards } from './card-store.js'; import Card from './Card.svelte'; import CardForm from './CardForm.svelte'; let cardsList $: cardsList = $cards.reduce((acc, card) => { acc[card.listId] = acc[card.listId] || [] acc[card.listId].push(card) return acc }, {}) </script> {#each [1,2,3] as idx} <h2>List: {idx}</h2> <ul> {#each cardsList[idx] as card} <Card {...card} /> {/each} </ul> <CardForm listId={idx} /> {/each}Y elimine la entrada cardsGroupedByList de la tienda de tarjetas
editar: no estoy seguro de que esto sea muy diferente de lo que haces, ya que la estructura se vuelve a calcular cada vez de todos modos: /