Skip to content

Instantly share code, notes, and snippets.

@ox
Last active January 5, 2023 23:32
Show Gist options
  • Save ox/6ed13e7a0b0f265a6996f2ce32010209 to your computer and use it in GitHub Desktop.
Save ox/6ed13e7a0b0f265a6996f2ce32010209 to your computer and use it in GitHub Desktop.
Example Lit data store using immer and ulid
import produce from "https://cdn.jsdelivr.net/npm/immer/+esm";
import { ulid } from "https://unpkg.com/ulid@2.3.0/dist/index.esm.js";
// BaseStore is responsible for managing subscribers to the store and
// notifying them of changes.
class BaseStore {
constructor() {
this.subscribers = new Set([]);
}
subscribe(host) {
this.subscribers.add(host);
}
unsubscribe(host) {
this.subscribers.delete(host);
}
updateSubscribers() {
this.subscribers.forEach(host => host.requestUpdate());
}
}
// LocalStorageBackendStore persists the data when subscribers should be notified of changes.
// It also allows loading.
class LocalStorageBackendStore extends BaseStore {
constructor(key) {
super();
this.key = key;
}
persist(data) {
localStorage.setItem(this.key, JSON.stringify(data));
}
load() {
return JSON.parse(localStorage.getItem(this.key));
}
updateSubscribers(data) {
this.persist(data);
super.updateSubscribers();
}
}
// TasksStore is a store that has localstorage persistence. Very basic CRUD actions
class TasksStore extends LocalStorageBackendStore {
constructor() {
super('tasks');
this.tasks = this.load() || [];
}
getTasks() {
return this.tasks;
}
getTask(id) {
return this.addTasktasks.find(task => task.id === id);
}
addTask(name, time) {
this.tasks = produce(this.tasks, draft => {
draft.push({id: ulid(), name, time});
});
this.updateSubscribers(this.tasks);
}
editTask(id, changes = {}) {
this.tasks = produce(this.tasks, draft => {
const idx = this.tasks.findIndex(task => task.id === id);
if (idx < 0) {
return;
}
Object.assign(draft[idx], changes);
});
this.updateSubscribers(this.tasks);
}
removeTask(id) {
this.tasks = produce(this.tasks, draft => {
const idx = this.tasks.findIndex(task => task.id === id);
if (idx < 0) {
return;
}
draft = draft.splice(idx, 1);
});
this.updateSubscribers(this.tasks);
}
}
// The actual data is stored in a singleton here so all LitElements see the same
// data and get notified of the same changes.
const store = new TasksStore();
// LitElements subscribe to this ReactiveController to receive updates to changes
// in the store, as well as make changes so that other elements can see them.
export default class TasksControler {
constructor(host) {
this.host = host;
host.addController(this);
this.store = store;
}
hostConnected() {
store.subscribe(this.host);
}
hostDisconnected() {
store.unsubscribe(this.host);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment