Комментарии 13
Похоже на Hookstate
Кейсы с возможными устаревшими пропсами и зомби-чилдами не проверяли?
Расскажите, какие фичи используемого вами стейт-менеджера вы особенно цените.
В МобХ: тонкие оптимизации "из коробки" с абсолютным минимумом лишнего кода (подписка на стейт по факту использования в отличии от безусловной подписки в хуке; компутеды; экшены), синхронное обновление всех производных стейтов, простые мутабельные обновления развесистых объектов.
Спасибо за комментарий.
Кейсы с возможными устаревшими пропсами и зомби-чилдами не проверяли?
На сколько смог разобраться, данные "баги" больше на плечах пользователя, чем на библиотеке. Ну я повторюсь, что в частности с МобХ не достаточно знаком.
В первом случаи пропсы должны быть указаны в списке зависимостей (и, соответственно, акшен зависящий от пропов должен запускаться синхронно через эффект).
Во втором случаи, при использовании не-локального состояния лучше не делать никаких предположений о текущем состоянии, оно может быть любым (в рамках объявленного типа).
подписка на стейт по факту использования в отличии от безусловной подписки в хуке
Тут соглашусь, такая функция должна присутствовать даже в минимальном наборе. Будем добавлять возможность указания используемых полей объекта в хуке, по типу списка зависимостей.
возможность указания используемых полей объекта в хуке
Это важный поинт, но я говорил о другом. Пример:
const Comp = observer(() => {
...
if (...error...) {
return <div>error!!1</div>
}
return <div>{store.text}</div>
});
store - некий мобиксовый стор, из которого читаем (и подписываемся на) наблюдаемое поле text. И если мы не добрались до этой ветки, а например вышли из-за error, то не читаем и не подписываемся.
Извините пожалуйста, но разрешите докопаться.
редьюсер 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 требования. И одно из них тут нарушено.
Зачем вам редьюсеры? Уверен, что без них код получился бы проще. Я уже писал ранее, что это ненужное усложнение в Redux и useReducer:
https://habr.com/ru/post/546606/
https://github.com/sergeysibara/unusual-hooks#usestatewithupdaters---usereducer-alternative
С редьюсерами такая ситуация, что относительно простые состояния (например, представляемые одним фундаментальным объектом JS без вложенностей) на них реализовать проще/понятнее и субъективно красивее. Именно на такие случаи в первую очередь и рассчитана эта библиотека: когда приложению требуется простое состояние с глобальной видимостью.
Сложная же логика с кучей акшенов и состоянием представляемым множеством связанных объектов удобнее реализовывается через класс / объект с методами.
Как и везде, нет универсального решения лучшего во всех случаях.
Серьезно? Пожалуйста, используйте Javascript'овые getters/setters когда вы пишите стейт менеджеры, в чем проблема то? Это намного сократит и упростит код, который нужно писать. В таком виде как вы это сделали это никуда не годится. Либо можете вообще не заморачиваться и взять MobX, там уже давным давно все сделано по уму и с максимальным удобством использования.
Whoosh — минималистичный менеджер состояний React