State Store

The great thing about Markup state is the fact that it is a standalone API that works great witht the template itself.

What this allows you to do is manage shared/global state away from the component and inject them directly into the template or perform side effects where needed. All that without worrying about subcriptions and cleanups.

Create a state store

Take for example this todos state store:

typescript
1// src/stores/todos.ts2 3type UUID = `${string}-${string}-${string}-${string}-${string}`4 5export interface Todo {6    id: UUID7    name: string8    description: string9    status: 'done' | 'pending' | 'removed'10    dateCreated: Date11    dateLastUpdated: Date12}13 14const [todos, updateTodos] = state<Todo[]>([])15 16export const todoList = todos

As you can see, we can create a file dedicated to manage a particular state we want to use in multiple places in our application.

Consuming the store state

We don't have to worry about subscription when it comes to rendering this data, we can inject it directly into the template.

javascript
1import {todoList} from "./stores/todos"2 3const App = () => {4 5    const renderTodo = () => {...}6 7    // html will handle all subscribing and8    // unsubscribing from todoList state9    return html`10        <ul id="todos">11            ${repeat(todoList, renderTodo)}12        </ul>13    `14}

Easy enough, to perform something whenever this list changes, we can just use the effect.

javascript
1import { todoList } from './stores/todos'2 3const defaultTodosByStatus = { done: [], pending: [], removed: [] }4 5const [todosByStatus, updateTodosByStatus] = state(defaultTodosByStatus)6 7// effect will handle subscribing to the todoList state8const unsubFromEffect = effect(() => {9    updateTodosByStatus(10        todoList().reduce((acc, todo) => {11            if (!acc[todo.status]) {12                acc[todo.status] = []13            }14 15            acc[todo.status].push(todo)16 17            return acc18        }, defaultTodosByStatus)19    )20})21 22// call "unsubFromEffect" to unsubscribe from todoList state

Define store actions

Because the store is simply a file, we can expose functions that perform changes in the data without exposing the logic or complexity of the state.

typescript
1// src/stores/todos.ts2 3...4 5export const createTodo = (name: string) => {6  const dateCreated = new Date();7  const todo: Todo = {8    id: crypto.randomUUID(),9    name,10    description: "",11    status: "pending",12    dateCreated,13    dateLastUpdated: dateCreated14  }15 16  updateTodos(prev => [...prev, todo])17}18 19export const updateTodo = (id: UUID, data: Partial<Todo>) => {20    updateTodos(prev => prev.map(todo => {21        if(todo.id === id) {22            return {23                ...todo,24                name: data.name ?? todo.name,25                description: data.description ?? todo.description,26                status: data.status ?? todo.status,27                dateLastUpdated: new Date()28            }29        }30 31        return todo;32    }))33}34 35export const deleteTodo = (id: UUID) => {36    updateTodos(prev => prev.filter(todo => {37        return todo.id !== id;38    }))39}40 41export const clearTodos = () => {42    updateTodos([])43}

These actions can be whatever you want. They can

Data storage and state management does not have to be complex and all you need from here is use the APIs readily available in the environment to do whatever you want.

Look at this example of todo state store with localstorage.

edit this doc