Как стать автором
Обновить

Комментарии 13

Похоже на Hookstate

Кейсы с возможными устаревшими пропсами и зомби-чилдами не проверяли?

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

В МобХ: тонкие оптимизации "из коробки" с абсолютным минимумом лишнего кода (подписка на стейт по факту использования в отличии от безусловной подписки в хуке; компутеды; экшены), синхронное обновление всех производных стейтов, простые мутабельные обновления развесистых объектов.

Спасибо за комментарий.

Кейсы с возможными устаревшими пропсами и зомби-чилдами не проверяли?

На сколько смог разобраться, данные "баги" больше на плечах пользователя, чем на библиотеке. Ну я повторюсь, что в частности с МобХ не достаточно знаком.
В первом случаи пропсы должны быть указаны в списке зависимостей (и, соответственно, акшен зависящий от пропов должен запускаться синхронно через эффект).
Во втором случаи, при использовании не-локального состояния лучше не делать никаких предположений о текущем состоянии, оно может быть любым (в рамках объявленного типа).

подписка на стейт по факту использования в отличии от безусловной подписки в хуке

Тут соглашусь, такая функция должна присутствовать даже в минимальном наборе. Будем добавлять возможность указания используемых полей объекта в хуке, по типу списка зависимостей.

 

возможность указания используемых полей объекта в хуке

Это важный поинт, но я говорил о другом. Пример:

const Comp = observer(() => {
  ...
  if (...error...) {
    return <div>error!!1</div> 
  }
  return <div>{store.text}</div>
});

store - некий мобиксовый стор, из которого читаем (и подписываемся на) наблюдаемое поле text. И если мы не добрались до этой ветки, а например вышли из-за error, то не читаем и не подписываемся.

Просто сначала подумал, что store.text явно указывается в списке зависимостей до его использования (и пока не указан, не доступен пользователю). Интересная фитча. Попробую поиграть с оборачиванием store в `Proxy` для автоматического детектирования чтения свойств. Еще раз благодарю за пример.

Извините пожалуйста, но разрешите докопаться.

редьюсер toLocalStorage(), позволяющий сохранять Shared State в localStorage;

Редьюсер по определению своему - это чистая функция. Если у вас там возможны сайд-эффекты, то это уже middleware

Хук use() как функция-член объекта, а не как отдельная функция.

В реакте есть определенная конвенция, что хуками являются только функции, начинающиеся с use*. Своим именованием вы ломаете их eslint плагин, devtools и возможно еще всякий другой тулинг.

https://github.com/AlexIII/whoosh/blob/main/src/whoosh.ts#L58

А зачем вы фризите входной объект? С одной стороны понятно, чтобы его никто не вздумал мутировать, но с другой стороны, это должно решаться иными средствами, например, типами.

https://github.com/AlexIII/whoosh/blob/main/src/whoosh.ts#L37

Асинхронный scheduling внушает опасение. Можно попать в infinite loop, который очень сложно сдетектить, потому что из-за асинхронных обновлений переполнения стека не происходит. Кроме того, зомби-чилды из комментария выше так и возникают.

По-хорошему, лучше делегировать обновление стейта самому фреймворку. Сделать один Provider c useState, use-хук будет писать и читать из этого провайдера, а react сам разберется с порядком обновлений

Извините пожалуйста, но разрешите докопаться.

Благодарен, что вы решили это сделать.

Редьюсер по определению своему - это чистая функция.

toLocalStorage ведет себя как чистая функция. Он только записывает текущее значение состояния в localStorage не читая ничего обратно (это делает инициализатор) и не модифицируя состояние. Да, формально, это не чистая функция и, например, мемоизация невозможна (но и бессмысленна).

Своим именованием вы ломаете их eslint плагин, devtools

Упустил из виду, что средства разработки опираются на конвенции именования. Протестирую с eslint и devtools.

А зачем вы фризите входной объект? С одной стороны понятно, чтобы его никто не вздумал мутировать, но с другой стороны, это должно решаться иными средствами, например, типами.

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

К сожалению, типами это не решить. Да и plain JS пользователи, на сколько мне известно, существуют.

Асинхронный scheduling внушает опасение. Можно попать в infinite loop, который очень сложно сдетектить

Асинхронный вызов подписчиков был введен в основном как debouncing. В dev режиме планируется добавить детекцию бесконечного цикла обновлений с выводом предупреждения. (Эвристикой: считать количество вызовов подписчиков в единицу времени. Должно поймать основной процент проблем.)

По-хорошему, лучше делегировать обновление стейта самому фреймворку. Сделать один Provider c useState, use-хук будет писать и читать из этого провайдера, а react сам разберется с порядком обновлений

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

toLocalStorage ведет себя как чистая функция. Он только записывает текущее значение состояния в localStorage не читая ничего обратно (это делает инициализатор) и не модифицируя состояние. Да, формально, это не чистая функция

О_о. Это что угодно, но не чистая функция. Как формально, так и неформально. У pure function всего 2 требования. И одно из них тут нарушено.

И не спорю, не чистая. Я о том, что в конкретном use-case это несущественно, т.к. не вызовет каких-либо неприятностей.

Это в вашем варианте использования не существенно. Но раз вы делаете библиотеку в общем доступе, то и конвенциям сообщества соотвествовать надо. Тем более, что от вас многого и не требуется – достаточно поменять терминологию

Добавил в документацию соответстующее предупреждение.

С редьюсерами такая ситуация, что относительно простые состояния (например, представляемые одним фундаментальным объектом JS без вложенностей) на них реализовать проще/понятнее и субъективно красивее. Именно на такие случаи в первую очередь и рассчитана эта библиотека: когда приложению требуется простое состояние с глобальной видимостью.

Сложная же логика с кучей акшенов и состоянием представляемым множеством связанных объектов удобнее реализовывается через класс / объект с методами.

Как и везде, нет универсального решения лучшего во всех случаях.

Серьезно? Пожалуйста, используйте Javascript'овые getters/setters когда вы пишите стейт менеджеры, в чем проблема то? Это намного сократит и упростит код, который нужно писать. В таком виде как вы это сделали это никуда не годится. Либо можете вообще не заморачиваться и взять MobX, там уже давным давно все сделано по уму и с максимальным удобством использования.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации