Примеры на разных фреймворках

Один и тот же пакет devlink-statecore используется во всех пяти реализациях ниже. API ядра (createStore, setState, subscribe) идентичен — меняется только способ подписки под конкретный фреймворк.

Чистый JavaScript без фреймворков. Подписка на стор через store.subscribe и ручной ререндер DOM. Работает в любом браузере с поддержкой ES2020.

Установка
npm install devlink-statecore
index.html·html
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="utf-8" />
    <title>Todo — DevLink StateCore (Vanilla)</title>
  </head>
  <body>
    <input id="new-todo" placeholder="Новая задача" />
    <button id="add">Добавить</button>
    <ul id="list"></ul>
    <p id="counter"></p>

    <script type="module">
      import { createStore } from 'devlink-statecore';
      import { logger, persist } from 'devlink-statecore/middleware';

      const store = createStore(
        { items: [] },
        {
          name: 'VanillaTodo',
          middleware: [
            logger({ name: 'Todo', collapsed: true }),
            persist({ key: 'vanilla-todo' }),
          ],
        },
      );

      const $list = document.getElementById('list');
      const $counter = document.getElementById('counter');
      const $input = document.getElementById('new-todo');
      const $add = document.getElementById('add');

      function render(state) {
        $list.innerHTML = '';
        state.items.forEach((t) => {
          const li = document.createElement('li');
          li.textContent = t.text + (t.done ? ' ✓' : '');
          li.style.textDecoration = t.done ? 'line-through' : 'none';
          li.addEventListener('click', () => toggle(t.id));
          $list.appendChild(li);
        });
        $counter.textContent = 'Всего: ' + state.items.length;
      }

      function add() {
        const text = $input.value.trim();
        if (!text) return;
        store.setState((s) => ({
          items: [...s.items, { id: crypto.randomUUID(), text, done: false }],
        }));
        $input.value = '';
      }

      function toggle(id) {
        store.setState((s) => ({
          items: s.items.map((t) =>
            t.id === id ? { ...t, done: !t.done } : t,
          ),
        }));
      }

      store.subscribe((s) => render(s));
      $add.addEventListener('click', add);
      $input.addEventListener('keydown', (e) => e.key === 'Enter' && add());

      render(store.getState());
    </script>
  </body>
</html>

Хотите попробовать вживую?

Живое React-демо (Counter + Todo с persist) запущено на странице продукта.

Открыть демо →