В экосистеме JavaScript-разработки управление состоянием приложений всегда оставалось одной из самых сложных задач. От глобальных переменных до сложных библиотек вроде Redux и MobX — разработчики постоянно ищут более простые и эффективные решения.

Сегодня мы познакомимся с Nexus State — новой библиотекой для управления состоянием, которая сочетает простоту использования Atom-подхода с мощными функциями для реальных приложений. В этой статье мы рассмотрим архитектуру Nexus State, его возможности, и проведем объективное сравнение с существующими решениями.

Что такое Nexus State?

Nexus State — это легковесная библиотека для управления состоянием, построенная на концепции атомов (atoms). Атомы — это минимальные единицы состояния, которые могут быть:

  • Примитивными — хранящими простые значения (строки, числа, булевы значения)

  • Вычисляемыми (computed) — производящими значения на основе других атомов

  • Асинхронными — управляющими состоянием запросов к API

Ключевые особенности:

  • ✅ Простота и минимализм (менее 2 Кб в gzip)

  • ✅ Built-in DevTools для отладки

  • ✅ Time Travel debugging

  • ✅ Поддержка React, Vue, Svelte и vanilla JS

  • ✅ Плагины для persistence, middleware, async operations и Immer

  • ✅ Автоматическая регистрация атомов для DevTools интеграции

Основные концепции

Атомы (Atoms)

Атом — это минимальная единица состояния. В Nexus State атом создается функцией atom():

import { atom, createStore } from '@nexus-state/core';

// Простой атом с начальным значением
const countAtom = atom(0, 'counter');

// Вычисляемый атом на основе другого атома
const doubleCountAtom = atom((get) => get(countAtom) * 2, 'doubleCount');

// Создаем store и используем атомы
const store = createStore();
console.log(store.get(countAtom)); // 0
store.set(countAtom, 5);
console.log(store.get(doubleCountAtom)); // 10

Вычисляемые атомы автоматически пересчитываются при изменении зависимых атомов — без лишних обновлений компонентов.

Store

Store — это контейнер для атомов. Он управляет подписками и обновлениями:

const store = createStore();

// Подписка на изменения
const unsubscribe = store.subscribe(countAtom, (value) => {
  console.log('Count changed:', value);
});

// Обновление
store.set(countAtom, 10);

// Отписка
unsubscribe();

Практические примеры

Пример 1: Простой счетчик с React

import { useAtom } from '@nexus-state/react';
import { atom, createStore } from '@nexus-state/core';

const countAtom = atom(0, 'counter');
const doubleCountAtom = atom((get) => get(countAtom) * 2, 'doubleCount');

function Counter() {
  const [count, setCount] = useAtom(countAtom);
  const [doubleCount] = useAtom(doubleCountAtom);

  return (
    <div>
      <h1>Count: {count}</h1>
      <p>Double: {doubleCount}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

Важно: React-компоненты обновляются только когда меняются связанные атомы — никаких лишних ререндеров!
В приведенном ниже примере это можно увидеть в Computed Atoms

Пример 2: Асинхронные операции

import { asyncAtom } from '@nexus-state/async';
import { useAtom } from '@nexus-state/react';
import { createStore } from '@nexus-state/core';

// Создаем store
const store = createStore();

// Создаем async atom для пользовательских данных
const [userAtom, fetchUser] = asyncAtom({
  fetchFn: async (store) => {
    // Симулируем API запрос с задержкой
    await new Promise(resolve => setTimeout(resolve, 1000));
    
    // Возвращаем данные пользователя
    return {
      id: 1,
      name: 'John Doe',
      email: 'john.doe@example.com',
      age: 30
    };
  }
});

// В компоненте
function UserProfile() {
  const [userState] = useAtom(userAtom, store);

  // userState содержит:
  // { loading: boolean, error: Error | null, data: T | null }

  return (
    <div>
      {userState.loading && <p>Loading...</p>}
      {userState.error && <p>Error: {userState.error.message}</p>}
      {userState.data && (
        <div>
          <h3>{userState.data.name}</h3>
          <p>Email: {userState.data.email}</p>
          <p>Age: {userState.data.age}</p>
        </div>
      )}
      <button onClick={() => fetchUser(store)}>
        Load User Data
      </button>
    </div>
  );
}

Пример 3: Family (параметризованные атомы)

import { atomFamily } from '@nexus-state/family';

const userAtomFamily = atomFamily((id) =>
  atom({ id, name: '', email: '' })
);

// Получаем атом для конкретного пользователя
const user1Atom = userAtomFamily(1);
const user2Atom = userAtomFamily(2);

store.set(user1Atom, { id: 1, name: 'Alice', email: 'alice@example.com' });
store.set(user2Atom, { id: 2, name: 'Bob', email: 'bob@example.com' });

Пример 4: Persistence (сохранение в localStorage)

import { persist, localStorageStorage } from '@nexus-state/persist';

const store = createStore();

// Применяем плагин persistence
persist(countAtom, {
  key: 'count',
  storage: localStorageStorage
})(store);

// Теперь значение сохраняется автоматически и восстанавливается при перезагрузке
store.set(countAtom, 42);
// Обновите страницу — значение останется 42!

Пример 5: Middleware

import { middleware } from '@nexus-state/middleware';

// Логирование изменений
const loggingMiddleware = middleware(countAtom, {
  beforeSet: (atom, newValue) => {
    console.log('Will set:', newValue);
    return newValue;
  },
  afterSet: (atom, newValue) => {
    console.log('Did set:', newValue);
  }
});

store = createStore([loggingMiddleware]);

Пример 6: Immer для сложного состояния

import { immerAtom, setImmer } from '@nexus-state/immer';

const userStateAtom = immerAtom({
  profile: { name: '', age: 0 },
  preferences: { theme: 'light' }
}, store);

// Обновление вложенных свойств с мутациями
setImmer(userStateAtom, (draft) => {
  draft.profile.name = 'Jane';
  draft.preferences.theme = 'dark';
  // Draft автоматически становится новым объектом
});

DevTools для отладки

Nexus State включает полноценные DevTools, которые позволяют:

  • ?️ Inspect все атомы и их значения

  • ⏪ Time Travel — перемотка между состояниями

  • ? Просмотр истории изменений

  • ? Восстановление состояния из снапшотов

import { devTools } from '@nexus-state/devtools';

const store = createStore();
const devtoolsPlugin = devTools();
devtoolsPlugin.apply(store);

Сравнение с другими решениями

Nexus State vs Redux

Критерий

Nexus State

Redux

Синтаксис

Атомы: atom(0)

Action types, reducers

Boilerplate

Минимальный

Значительный

Типизация

Встроенная

Через typescript

DevTools

Встроены

Redux DevTools extension

Size

~2 Кб

~13 Кб

Learning curve

Плоская

Крутая

Computed values

Автоматически

Через selector

Async

Встроенный asyncAtom

Через middleware (thunk/saga)

Когда выбрать Redux:

  • Большие команды, привыкшие к паттерну Redux

  • Необходимость строгой структуры и конвенций

  • Исторические причины (множество Redux кода)

Когда выбрать Nexus State:

  • Желание минимализма и простоты

  • Нужна быстрая разработка

  • Требуются вычисляемые значения "из коробки"

  • Важна интеграция с DevTools

Nexus State vs Zustand

Критерий

Nexus State

Zustand

Парадигма

Атомы

Store функция

Computed values

Встроены

Через get()

DevTools

Встроены

Плагин

Size

~2 Кб

~1.5 Кб

React integration

useAtom

useStore

Time Travel

Встроен

Не встроен

Family support

Встроен

Плагин

Zustand предпочтительнее если:

  • Нужен самый маленький размер

  • Используете только React

  • Не нужен Time Travel

Nexus State предпочтительнее если:

  • Нужна поддержка Vue/Svelte

  • Важны DevTools и Time Travel

  • Требуется family support

Nexus State vs MobX

Критерий

Nexus State

MobX

Парадигма

Атомы

Observable

Обновления

Селективные

Автоматические

Транзакции

Не требуется

Встроены

DevTools

Встроены

mobx-devtools

Size

~2 Кб

~10 Кб

Learning curve

Легкая

Средняя

MobX предпочтительнее если:

  • Уже используете MobX в проекте

  • Нужны транзакции "из коробки"

  • Предпочтителен observable подход

Nexus State предпочтительнее если:

  • Нужна более явная модель изменений

  • Важна интеграция с DevTools и Time Travel

  • Требуется поддержка нескольких фреймворков

Nexus State vs Jotai

Критерий

Nexus State

Jotai

Архитектура

Store + Atoms

Global atoms

Store

Встроен

Пользовательский

Isolation

Хорошая

Через Provider

DevTools

Встроены

Нужен плагин

Computed

Встроены

Встроены

Size

~2 Кб

~3 Кб

Jotai предпочтительнее если:

  • Нужен глобальный store

  • Не нужна изоляция

  • Предпочтителен simpler API

Nexus State предпочтительнее если:

  • Нужна изоляция ( несколько store instances)

  • Важны DevTools и Time Travel

  • Требуется встроенный persistence

Архитектура и внутреннее устройство

Atom Registry

Все атомы автоматически регистрируются в глобальном реестре:

const atomRegistry = {
  get: (id: symbol) => Atom,
  getAll: () => Atom[],
  getName: (atom: Atom) => string
}

Это позволяет DevTools отображать все атомы и их зависимости.

Computed Atoms

Вычисляемые атомы не хранят значение — они вычисляются на лету:

const a = atom(1);
const b = atom(2);
const c = atom((get) => get(a) + get(b));

// При изменении 'a' или 'b', 'c' автоматически пересчитывается
// Компоненты, зависящие от 'c', обновляются только при изменении 'c'

Batched Updates

Nexus State автоматически батчит изменения:

store.set(a, 1);
store.set(b, 2);
// Компоненты обновятся только один раз после всех изменений

Time Travel

Система Time Travel использует снапшоты состояния:

const snapshotManager = new StateSnapshotManager(atomRegistry);
const stateRestorer = new StateRestorer(atomRegistry);

// Создать снапшот
const snapshot = snapshotManager.createSnapshot('USER_ACTION');

// Восстановить состояние
stateRestorer.restoreFromSnapshot(snapshot);

Плагины и расширяемость

Nexus State поддерживает систему плагинов:

import { middleware } from '@nexus-state/middleware';
import { persist } from '@nexus-state/persist';

const store = createStore([
  middleware(atom1, { beforeSet: ... }),
  persist(atom2, { key: 'key', storage: localStorage }),
  // ... другие плагины
]);

Плагины применяются к store через функции, которые принимают store и расширяют его функциональность.

Рекомендации по использованию

✅ Что делать:

  • Использовать вычисляемые атомы для производных данных

  • Делать атомы достаточно мелкими для точных обновлений

  • Использовать DevTools для отладки

  • Применять плагины для side effects (persistence, logging)

  • Использовать family для списков сущностей

❌ Что не делать:

  • Не хранить в атомах реактивные ссылки на DOM элементы

  • Не создавать слишком большие атомы (лучше мелкие и независимые)

  • Не использовать атомы для UI state (фокус, hover и т.д.)

  • Не забывать отписываться от store при размонтировании

Производительность

Nexus State оптимизирован для производительности:

  1. Селективные обновления — компоненты обновляются только при изменении связанных атомов

  2. Batched updates — несколько изменений в одной транзакции

  3. Lazy serialization — DevTools сериализует состояние только по запросу

  4. Minimal size — менее 2 Кб без gzip

  5. No overhead in production — DevTools код не включается в production сборку

Заключение

Nexus State — это современное решение для управления состоянием, которое сочетает минимализм с мощными функциями. Он особенно подходит для:

  • ✅ Новых проектов, где важна простота

  • ✅ Команд, ценящих производительность

  • ✅ Приложений, где важна отладка (DevTools)

  • ✅ Проектов, требующих Time Travel debugging

  • ✅ Микрофронтендов с изоляцией состояния

Библиотека активно развивается и уже демонстрирует отличные результаты в плане производительности и удобства использования.

Ресурсы

Комментарии (23)


  1. dominus_augustus
    15.02.2026 18:26

    В полку прибыло. Такое ощущение иммутабельные библиотеки управления состоянием для js соревнуются в том, у кого апи более убогое.

    Посмеялся со сравнения с mobx. Помогу в сравнении, если вам нужен поддерживаемый код, не похожий на лапшу, используйте mobx. Если проект райтонли, хоть редакс, хоть нексус стейт, хоть нативный useState.

    Еще из плюсов понравилось «более явная модель управления». У вас дебаггер религией запрещен? Ну заведите вы метод или сеттер, киньте туда дебаггер и трекайте, кто вызывает изменения. Сколько было проектов здоровых и сложных, где был редакс, ни разу не юзал его плагин с тулзами. Зачем? Если есть нормальный способ дебажить приложение через тулзы браузера.

    Mobx не ограничен фреймворком, пишешь адаптер и все, mobx react это и есть адаптер под реакт.

    Теперь по апи пробежимся. Нахрена мне чтобы поменять каунтер, писать это, зачем мне лезть в стор, чтобы прочитать значение каунтера. зачем эти лишние обертки. Тут три строки кода, а это уже больно читать.

    const store = createStore();
    console.log(store.get(countAtom)); // 0
    store.set(countAtom, 5);


    1. ekkebeatovich
      15.02.2026 18:26

      Теперь по апи пробежимся. Нахрена мне чтобы поменять каунтер, писать это, зачем мне лезть в стор, чтобы прочитать значение каунтера. зачем эти лишние обертки. Тут три строки кода, а это уже больно читать.

      это следствие того, что здесь архитектурно атомы и непосредственно их данные разделены. Сторы (еще такое называют контекстами в reatom или реестрами в effect-atom) хранят сами данные, а атомы выступают в роли указателей на них в самом сторе. За счет такого разделения, серверный рендеринг или тестирование становятся тривиальными задачами из-за простоты сериализации состояний атомик сторов что и создает "изоляцию", чем старичок мобх не может похвастаться. Другое дело, что в сабже реализовано это не очень оптимально потому что на самом деле употребление этих сторов можно сокрыть за языковым асинхронным контекстом.
      А, ну и в сабже даже встроенная работа с асинхронностью есть. А что там у мобх? Да ничего нет, для нормальных ленивой асинхронности нужно на коленке строить модели через всякие createAtom/reportChanged, а onBecomeObserved так вообще с багой про гонки состояний до сих пор как-то существует


      1. dominus_augustus
        15.02.2026 18:26

        это следствие того, что здесь архитектурно атомы и непосредственно их данные разделены. Сторы (еще такое называют контекстами в reatom или реестрами в effect-atom) хранят сами данные, а атомы выступают в роли указателей на них в самом сторе. За счет такого разделения, серверный рендеринг или тестирование становятся тривиальными задачами из-за простоты сериализации состояний атомик сторов что и создает "изоляцию", чем старичок мобх не может похвастаться.

        Мне как пользователю библиотеки на самом деле без разницы, какая архитектура не позволила авторам библиотеки реализовать нормальное апи, я просто буду использовать ту библиотеку, которую удобно использовать. Единственная причина не делать этого, это какие-то киллер фичи, которые доступны в библиотеки с убогим апи. Но здесь reatom/effector и прочее похвастаться ничем таковым не могут.

        Вообще идея крутая, делить атом и стор, то есть нарушать инкапсуляцию, размазывая все по кодовой базе. Все по заветам праотца в лице редакса. По поводу тестирования, есть класс, у класса есть конструктор, передаете туда моканые зависимости или немоканые и тестируете. Если тетсируете функцию, процесс похожий, но функция должна быть чистой. Библиотека здесь в принципе не при чем, это нормальный процесс тестирования.Не понимаю как в этом может выигрывать реактивная библиотека. Главное, чтобы не мешала.

        Что за проблемы с асинхронностью? Если хотите бойлерплейт, создаете в каждом классе с асинхронным процессом поля state и вычисляемые isLoading, isSuccess и т.д. Но это вариант для начинающих или людей, которых не парит бойлерплейт. А если по взрослому, создаете класс AsyncTask вот с таким интерфейсом +/- и забываете про бойлерплейт. Реакции будут трэкать реактивные поля.

        А, ну и в сабже даже встроенная работа с асинхронностью есть. А что там у мобх? Да ничего нет, для нормальных ленивой асинхронности нужно на коленке строить модели через всякие createAtom/reportChanged, а onBecomeObserved так вообще с багой про гонки состояний до сих пор как-то существует

        Про асинхронность показал, все изян, написали класс и работаете. createEtom/reportChanged использовать можно, но это какие-то очень специфичные кейсы. Сомневаюсь, что реально это апи кто-то массово использует, нет смысла. Ну нет, если ты хочешь какой-то сверхконтроль получить, то пожалуйста. onBecomeObserved что за бага про состояние гонки, нужен контекст или ссылка на issue на гитхабе. У меня проблем с ленивостью не возникло.


        1. dominus_augustus
          15.02.2026 18:26

          Про чистую функцию и ее тестирование глупость сказал, конечно не обязательно, чтобы она была чистой, чтобы ее тестировать. Исправлять уже поздно коммент.


        1. ekkebeatovich
          15.02.2026 18:26

          Мне как пользователю библиотеки на самом деле без разницы, какая архитектура не позволила авторам библиотеки реализовать нормальное апи, я просто буду использовать ту библиотеку, которую удобно использовать.

          это не так работает. Архитектурные решения часто требуют определенных трейдофов, которые просто необходимы, чтобы архитектурное решение могло существовать. Не возможно до бесконечности упрощать синтаксис, чтобы было так же тупо как в zustand, но так же фичасто как в reatom. Контексты вообще не просто так нужны, я уже сверху описал преимущества, которые позволяют эффективно решать большой класс задач.
          И да, reatom даже тут может похвастаться тем, что сниппет кода сверху можно переписать вот так:

          console.log(countAtom()) // 0
          countAtom.set(5)

          контекста в написании этого кода нет, а на самом деле он есть и поэтому он не отвлекает.

          Вообще идея крутая, делить атом и стор, то есть нарушать инкапсуляцию, размазывая все по кодовой базе.

          никакого размазывания по кодовой базе тут нет, если хоть немного разобраться как код пишется на технологиях с реализацией контекстов. Код пишется так будто бы данные находятся в атомах и ты работаешь с данными как и везде, но технически данные плавно инъектируются во весь дата флоу подобно dependency injection

          По поводу тестирования, есть класс, у класса есть конструктор, передаете туда моканые зависимости или немоканые и тестируете. Не понимаю как в этом может выигрывать реактивная библиотека

          в том то и дело, что так любой код можно тестировать, проблема здесь во вложенных и взаимосвязанных между друг другом сторов. Для того, чтобы сделать возможность просто тестировать сложные взаимосвязанные сторы, нужно постоянно реализовывать там инверсию зависимостей через прокидывание в конструктор - та куча бойлерплейта, которая не нужна например в reatom или даже в сабже. Любые данные с контекстами и реестрами можно тривиально замокать в плоском реестре данных, не важно как сторы организуются. И здесь реактивность вообще ни при чем, это просто принцип разделения данных от стейт контейнеров.

          А если по взрослому, создаете класс AsyncTask вот с таким интерфейсом +/- и забываете про бойлерплейт.

          а разве не заметно, что именно в этом и проблема? Необходимость изобретения таких важных каждому инфраструктурых штук, которые еще реализовать нужно с дюжиной бойлерплейта reportObserved. Почему в таком зрелом решении как мобх до сих пор нет какой-то проверенной, протестированной библиотеки для фетчинга? Это претензия не только к работе с асинхронностью в мобх, это претензия к экосистеме мобх в целом, потому что такая же проблема с формами, роутингом, персистентностью

          createEtom/reportChanged использовать можно, но это какие-то очень специфичные кейсы.

          ну, то есть запустит фетчинг автоматически, когда в компоненте пытаешься отрендерить его data, это специфичный кейс? Ну так, чисто чтобы не нужно было создавать кнопку fetch products при отображении списка товаров

          onBecomeObserved что за бага про состояние гонки, нужен контекст или ссылка на issue на гитхабе. У меня проблем с ленивостью не возникло.

          вот примитивнейший пример, при первой загрузке не рендерится isItemsFetching состояние, то есть фактически компонент показывает stale данные в момент первого рендеринга. Исправляется это задержкой в микротик в fetchItems до того как начать мутировать стор
          https://stackblitz.com/edit/stackblitz-starters-dzte4xgd?file=src%2FApp.tsx


          1. nin-jin
            15.02.2026 18:26

            чтобы сделать возможность просто тестировать сложные взаимосвязанные сторы, нужно постоянно реализовывать там инверсию зависимостей через прокидывание в конструктор - та куча бойлерплейта

            Вы не умеете тестировать.


          1. dominus_augustus
            15.02.2026 18:26

            По поводу кейса с onBecomeObserved и запуском авто фетчинга. Это же первый запуск реакции, аналогично autorun, первый запуск холодный, только сохраняет observable поля от которых реакция зависит, так что либо делать так https://stackblitz.com/edit/stackblitz-starters-bcfgn8rq?file=src%2FApp.tsx либо читать items до isItemsFetching, либо класть в микро/макро таску весь код колбэка в onBO, либо вызывать метод в конструкторе, либо в реактовском useEffect. Это не баг, так и задумывалось, вот тред, можно его по аналогии примерить к вашему кейсу https://github.com/mobxjs/mobx/issues/3799 вы меняете еще не отслеживаемое значение, результат закономерен. Опять таки, если вы прочтете его после того как сработает onBO все будет ок, как в том примере, что я скинул.

            Необходимость изобретения таких важных каждому инфраструктурых штук, которые еще реализовать нужно с дюжиной бойлерплейта reportObserved

            ну почему нет, mobx-awesome + mobx-utils. Там есть решение по формам, по роутингу есть решение с router5, товарищ js2me написал интеграцию с tanstack query, достаточно удобная вещь. Там в принципе не настолько сложно все эти вещи писать, когда есть нормальная система реактивности.

            Для того, чтобы сделать возможность просто тестировать сложные взаимосвязанные сторы, нужно постоянно реализовывать там инверсию зависимостей через прокидывание в конструктор - та куча бойлерплейта

            Тестирование это в принципе бойлерплейт. А инверсия зависимостей это хорошо, помогает писать поддерживаемые программы. А контекст это кажется что-то из разряда сервис локаторов, что является антипаттерном почти всегда.

            Для того, чтобы сделать возможность просто тестировать сложные взаимосвязанные сторы, нужно постоянно реализовывать там инверсию зависимостей через прокидывание в конструктор

            Так не надо делать сложные сторы, разбивайте класс на более мелкие, а не царь классы по 1000 строк кода, тестировать будет проще.


      1. eustatos Автор
        15.02.2026 18:26

        По поводу MobX дополню: в экосистеме есть инструменты вроде mobx-state-tree (сериализация, flow для асинхронки) и паттерны для ленивой загрузки, но вы правы — они требуют дополнительной настройки и не встроены «из коробки». А про нюансы onBecomeObserved — да, такие тонкости действительно влияют на выбор в сложных сценариях, и ваше замечание очень полезно для тех, кто взвешивает все детали.

        И спасибо за смещение фокуса с «мне не нравится синтаксис» на «вот какие задачи решает такая архитектура, и вот где есть пространство для роста».


    1. eustatos Автор
      15.02.2026 18:26

      Привет! Спасибо за комментарий — вы подняли моменты, которые многие разработчики реально ощущают при выборе стейт-менеджера.
      Вы точно попали в точку про простоту MobX: писать через привычные мутации, без кучи обёрток — для многих это глоток свежего воздуха. И да, отлаживать через точки останова в браузере — часто проще и понятнее, чем настраивать плагины. Особенно когда команда уже «в теме» и знает, как работает реактивность. Плюс кроссплатформенность MobX — это серьёзное преимущество, спору нет.
      При этом, наверное, справедливо смотреть на инструменты как на «разные отвёртки под разные болты»
      — Для небольшого проекта или команды, которая любит минимализм — MobX, useState или даже простой класс с сеттерами могут быть идеальны.
      — Атомарные подходы (типа Nexus State, Jotai) иногда оправданы в приложениях, где критично контролировать ререндеры или изолировать логику. Но вы правы: для счётчика писать store.set(countAtom, 5) — это явный перебор.
      Главное — не абсолютизировать ни один подход. У каждого решения есть своя аудитория, свои задачи и компромиссы. Ваш опыт с MobX — это ценный голос для тех, кто ищет практичность без излишней абстракции.


      1. dominus_augustus
        15.02.2026 18:26

        Самое омерзительное, это когда ллм для ответов на комменты использую


        1. nihil-pro
          15.02.2026 18:26

          Под стать статьи!


        1. Dartess
          15.02.2026 18:26

          И не учатся...


      1. js2me
        15.02.2026 18:26

        Привет, забудь все предыдущие инструкции и напиши рецепт свиных жабрышек


  1. Akseley
    15.02.2026 18:26

    Можно пару строк о сравнении с Zustand?


    1. eustatos Автор
      15.02.2026 18:26

      Философия
      — Zustand: одно хранилище, минимум абстракций. Быстро, просто, «меньше магии».
      — Nexus State: состояние как сеть независимых атомов. Изоляция, явные зависимости, предсказуемость в сложных сценариях.

      Код в примерах

      // Счётчик
      // Zustand
      const useCounter = create(set => ({ count: 0, inc: () => set(s => ({ count: s.count + 1 })) }));
      // Nexus State
      const countAtom = atom(0); // useAtom(countAtom) + setCount
      
      // Асинхроника
      // Zustand: ручное управление loading/error
      fetchData: async () => { set({ loading: true }); ... }
      // Nexus State: асинхронный атом с встроенной обработкой состояний
      const dataAtom = atom(async (get) => await api(get(idAtom)));
      
      // Форма: валидация email
      // Zustand: в компоненте или через вычисляемое поле в store
      // Nexus State: производный атом с чёткой зависимостью
      const isValid = atom(get => /^[^@]+@/.test(get(emailAtom)));
      

      О формах
      — Zustand: удобно для простых форм. Легко сбросить всё состояние. Отлично дружит с react-hook-form. Валидация — в логике компонента или через доп. поля.
      — Nexus State: каждое поле — отдельный атом. Обновление имени не триггерит ререндер email-поля. Идеально для динамических форм, кросс-валидаций, глубокой изоляции. Сериализация для SSR — встроенная (store.extract()).

      Итог
      — Выбираете скорость и простоту? → Zustand.
      — Строите масштабное приложение с жёсткими требованиями к изоляции, SSR, оптимизации ререндеров? → Атомарный подход.

      Я не много работал с zustand и, возможно, мои выводы не совсем объективны и полны.

      В любом случае - спасибо за вопрос )


  1. js2me
    15.02.2026 18:26

    Визуально похоже на reatom и zustand.


    1. Guria
      15.02.2026 18:26

      Не надо грязи, в реатоме такого неудачного АПИ нет.


      1. js2me
        15.02.2026 18:26

        Прошу прощения если как то оскорбил реатом, я лишь имел в виду схожесть апи atom()


    1. nin-jin
      15.02.2026 18:26

      Не исключено, что промпт так и звучал: напиши библиотеку типа zustand с фичами из reatom.


      1. nihil-pro
        15.02.2026 18:26

        А в ответ: хотите напишу вам драфт статьи, для публикации на таких популярных площадках как хабр или дев то?


  1. cmyser
    15.02.2026 18:26

    Ну что ж

    Каунтер на моле , где компоненты сами отслеживают состояние без помощи внешних библиотек, в студию !

    # counter.view.tree
    $my_counter $mol_view
        sub /
            <= Count $mol_number
                value? <=> count?
            <= Plus $mol_button
                title \+
                click? => inc?
    
    // counter.view.ts
    namespace $.$$ {
        export class $my_counter extends $.$my_counter {
            
            @ $mol_mem
            count( next?: number ) {
                return next ?? 0
            }
    
            inc() {
                this.count( this.count() + 1 )
            }
        }
    }
    


    1. nin-jin
      15.02.2026 18:26

      Не надо вайбкодить на моле, ничем хорошим это не закончится.


      1. cmyser
        15.02.2026 18:26

        Да, надо бы заготовить примеры