43
loading...
This website collects cookies to deliver better user experience
svelte-entity-store
is to provide a simple, generic solution for storing collections of entity objects. Throwing an array of items into a basic writable
store doesn't scale well if you have a lot of items and need to quickly find or update one item in the store.npm i -s svelte-entity-store
Check out /examples for a working TodoMVC demo based on SvelteKit. More to come!
<script lang="ts">
import { entityStore } from 'svelte-entity-store'
// Define your entity interface
interface TodoItem {
id: string
description: string
completed: boolean
}
// Write a getter function that returns the ID of an entity (can be inlined in the constructor also)
// Currently number and string values are valid IDs
const getId = (todo: TodoItem) => todo.id
// Initialize the store
// (optional) the constructor accepts an Array as a second param
// ex: if you rehydrate state from localstorage
const store = entityStore<TodoItem>(getId)
// Get a derived store for every active todo
const activeTodos = store.get((todo) => todo.completed)
// toggle a todo
function toggle(id: string) {
store.update((todo) => ({ ...todo, completed: !todo.completed }), id)
}
// clear completed todos
function clearCompleted() {
store.remove((todo) => todo.completed)
}
</script>
{#each $activeTodos as todo (todo.id) }
// ... render your UI as usual
{/each}
svelte-entity-store
in plain old JavaScript is very similar, just skip the interface
definition and <Type>
casting.import { entityStore } from "svelte-entity-store";
// Define your entity interface
interface TodoItem {
id: string;
description: string;
completed: boolean;
}
// Write a getter function that returns the ID of an entity (can be inlined in the constructor also)
// Currently number and string values are valid IDs
const getId = (todo: TodoItem) => todo.id;
// Initialize the store
// (optional) the constructor accepts an Array as a second param
// ex: if you rehydrate state from localstorage
const store = entityStore<TodoItem>(getId);
interface
, you could also use type
if that's your thing. The store also needs to know how to get unique IDs for each item. Right now string
and number
IDs are supported, but this may be extended later.const items = [
// ... array of TodoItem's to populate the store with
];
const store = entityStore<TodoItem>(getId, items);
store.set(items)
immediately. This is particularly handy if you are rehydrating the store from cache or localstorage, similar to the TodoMVC example.get()
methods return readable stores to access the entities. The get()
method has multiple overrides to serve different uses like grabbing a single entity, filtered list of entities, or everything in the store.// Get one entity by ID
const item = store.get("abc-123");
// Get a list of entities by ID
const items = store.get([123, 456, 789]);
// Get a list of entities that match a filter function
const activeItems = store.get((todo) => !todo.completed);
// Or get every entity in the store
const allItems = store.get();
<script lang="ts">
// Create a computed property based on the get() results
$: activeItemsCount = $activeItems.count
</script>
// Directly access a single entity
<h1>{$item.title}</h1>
// Or loop over multiple entities
<ul>
{#each $allItems as item (item.id)}
<li class:completed={item.completed}>
{item.title}
</li>
{/each}
</ul>
get()
, set()
has a few different overrides. Calling set
will blow away any old entity state, if you need to keep some of the old entities' state check out update()
instead (below).// Replace the existing entity with ID 123, or add it if the ID doesn't exist yet
store.set({
id: 123,
description: "Todo #1",
completed: true,
});
// Or add/replace multiple todos at once
store.set([
// ... multiple todo objects
]);
update()
solves this, it should look very familiar.function toggleTodo(todo: TodoItem) {
return {
...todo,
completed: !todo.completed,
};
}
// Update a single entity by ID
store.update(toggleTodo, 123);
// In case you already have the entity object and don't want to call getId,
store.update(toggleTodo, todoObj);
// The same goes for lists of IDs or entities
store.update(toggleTodo, [123, 456]);
store.update(toggleTodo, $activeTodos);
// What if you want to only update entities that meet a filter condition?
store.update(toggleTodo, (todo) => todo.completed);
// Go crazy with it and run the update against every entity in the store
store.update(toggleTodo);
update()
// You can remove single entities by ID
store.remove(123)
// By list of IDs
store.remove([123, 456])
// Or remove every item that matches a filter
const isCompleted = (todo) => todo.completed)
store.remove(isCompleted)
update
and remove
, I realized there's no reason that remove
shouldn't let you pass in the entity objects similar to update
. Time for a github issue.v1.0.0
of store has 100% test coverage and a working TodoMVC example.svelte-entity-store
tests. It was particularly interesting figuring out a clean way to store subscriptions, i.e. to make sure subscribers get updated state or that subscribers aren't called if an API call didn't actually change the store at all.const allItems = store.get();
$sortedItems = $allItems.sort((a, b) => (a < b ? 1 : -1));
sort
parameter to all get()
overloads.