Tienda estatal

Lo mejor de Markup estado es el hecho de que es una API independiente que funciona muy bien con la propia plantilla.

Lo que esto le permite hacer es administrar el estado compartido/global fuera del componente e inyectarlos directamente en la plantilla o realizar efectos secundarios cuando sea necesario. Todo eso sin preocuparte por suscripciones y limpiezas.

Crear una tienda estatal

Tomemos, por ejemplo, este almacén estatal todos:

typescript
// src/stores/todos.ts

type UUID = `${string}-${string}-${string}-${string}-${string}`

export interface Todo {
    id: UUID
    name: string
    description: string
    status: 'done' | 'pending' | 'removed'
    dateCreated: Date
    dateLastUpdated: Date
}

const [todos, updateTodos] = state<Todo[]>([])

export const todoList = todos

Como puede ver, podemos crear un archivo dedicado a administrar un estado particular que queremos usar en varios lugares de nuestra aplicación.

Consumir el estado de la tienda

No tenemos que preocuparnos por la suscripción cuando se trata de representar estos datos, podemos inyectarlos directamente en la plantilla.

javascript
import {todoList} from "./stores/todos"

const App = () => {

    const renderTodo = () => {...}

    // html will handle all subscribing and
    // unsubscribing from todoList state
    return html`
        <ul id="todos">
            ${repeat(todoList, renderTodo)}
        </ul>
    `
}

Es bastante fácil, para realizar algo cada vez que esta lista cambia, podemos usar el efecto.

javascript
import { todoList } from './stores/todos'

const defaultTodosByStatus = { done: [], pending: [], removed: [] }

const [todosByStatus, updateTodosByStatus] = state(defaultTodosByStatus)

// effect will handle subscribing to the todoList state
const unsubFromEffect = effect(() => {
    updateTodosByStatus(
        todoList().reduce((acc, todo) => {
            if (!acc[todo.status]) {
                acc[todo.status] = []
            }

            acc[todo.status].push(todo)

            return acc
        }, defaultTodosByStatus)
    )
})

// call "unsubFromEffect" to unsubscribe from todoList state

Definir acciones de tienda

Debido a que el almacén es simplemente un archivo, podemos exponer funciones que realizan cambios en los datos sin exponer la lógica o la complejidad del estado.

typescript
// src/stores/todos.ts

...

export const createTodo = (name: string) => {
  const dateCreated = new Date();
  const todo: Todo = {
    id: crypto.randomUUID(),
    name,
    description: "",
    status: "pending",
    dateCreated,
    dateLastUpdated: dateCreated
  }

  updateTodos(prev => [...prev, todo])
}

export const updateTodo = (id: UUID, data: Partial<Todo>) => {
    updateTodos(prev => prev.map(todo => {
        if(todo.id === id) {
            return {
                ...todo,
                name: data.name ?? todo.name,
                description: data.description ?? todo.description,
                status: data.status ?? todo.status,
                dateLastUpdated: new Date()
            }
        }

        return todo;
    }))
}

export const deleteTodo = (id: UUID) => {
    updateTodos(prev => prev.filter(todo => {
        return todo.id !== id;
    }))
}

export const clearTodos = () => {
    updateTodos([])
}

Estas acciones pueden ser las que quieras. ellos pueden

El almacenamiento de datos y la gestión del estado no tienen por qué ser complejos y todo lo que necesita a partir de aquí es utilizar las API disponibles en el entorno para hacer lo que quiera.

Mire este ejemplo de todo state store with localstorage.

editar este documento