Комментарии 16
Immer позволяет создавать новое иммутабельное состояние за счет мутации текущего.
А зачем? Какой смысл работать с неизменяемый состоянием так, будто оно изменяемое, если можно просто работать с изменяемым?
Для React напишем кастомный hook:
Чем это в итоге отличается от использования обычного useState и его производных? выглядит один в один.
у которого также есть метод getValue, с помощью которого можно получить текущее состояние
Использование getValue на observabl'ах — code smell и допустимо только в крайних случаях.
Ну и да, реакт с обсерваблами — это штаны через голову надевать, по достаточно очевидным причинам.
А зачем? Какой смысл работать с неизменяемый состоянием так, будто оно изменяемое, если можно просто работать с изменяемым?
Смысл в том что Immer это просто утилита
const x = {foo: {bar: 0}}
const y = {foo: {bar: x.foo.bar + 1}}
и
const y = produce(x, draft => draft.foo.bar += 1)
Концептуально ничем не отличаются.
Чем это в итоге отличается от использования обычного useState и его производных? выглядит один в один.
Тем, что данные из стора вы можете использовать в любом компоненте. Для примера можно посмотреть другие вариантами использования https://codesandbox.io/s/github/simmor-store/react-simmor/tree/master/examples
Использование getValue на observabl'ах — code smell и допустимо только в крайних случаях.
К каким проблемам может привести его использование в контексте текущего примера?
Смысл в том что Immer это просто утилита
Это понятно. Я говорю — зачем оно надо, если можно писать просто draft.foo.bar += 1?
К каким проблемам может привести его использование в контексте текущего примера?
Дело не в проблемах, дело в том, что если ваша логика построена на getValue, значит, вам вообще не нужны обсерваблы.
Они в общем-то и не нужны — в рамках семантики реакта ф-я рендер это как раз подписка на обсервабл.
Поработав с MobX некоторое время, для себя пришел к выводу, что лично мне проще оперировать последовательностью иммутабельных состояний (наподобие Redux), чем логикой мутабельного состояния (наподобие MobX)
Оперируйте, разрешаю.
class Store {
@observable _stateHistory = [];
@computed get state() {
return this._stateHistory[this._stateHistory.length - 1];
}
updateState(draftState) {
this._stateHistory.push(toJS(draftState));
}
}
Логика для обмазывания этим других классов, чтоб каждое изменение состояния дёргало бы updateState — точно такая же, как и у вас.
А зачем? Какой смысл работать с неизменяемый состоянием так, будто оно изменяемое, если можно просто работать с изменяемым?
Кстати, присоединяюсь к этому вопросу. На коде выше особенно хорошо видно, как такой подход просто добавляет сложности на ровном месте, и вместо привязки изменяемых состояний друг к другу зависимостями, вы будете делать то же руками — сначала делая особо вам нужный иммутабельный стейт, а потом вручную добавлять реакции на смену этого иммутабельного стейта.
Логика для обмазывания этим других классов, чтоб каждое изменение состояния дёргало бы updateState — точно такая же, как и у вас.
Статья не про мутабельность vs имутабельность, это отдельная большая тема.
Как я написал в начале, это мое личное предпочтение, на основе моего опыта. Например у вас в _stateHistory хранятся полные копии всех измененных состояний, в случае с иммутабельностью части состояний могли бы переиспользоваться.
Например у вас в _stateHistory хранятся полные копии всех измененных состояний, в случае с иммутабельностью части состояний могли бы переиспользоваться.
Это вообще не имеет отношения к статье и тому, что вы в ней описываете. Наверните сверху на _stateHistory какой-нибудь Immutable.js — и будет переиспользоваться. Или напишите то же самое руками. Но это другая проблема, никак не связанная с управлением состоянием.
Наверните сверху на _stateHistory какой-нибудь Immutable.js
Зачем сверху наворачивать Immutable.js если с самого начала можно использовать имутабельность? Плюсы это тема для отдельной статьи, что то вы можете почитать например в документации Redux.
Вы хотите делать this.counter += 1 и где-то в запасе иметь историю состояний? Имейте, вам никто не запрещает. Вы можете её иметь и крутить каунтер, или не иметь её и всё так же крутить каунтер. Механизм самого управления состоянием от этого не меняется.
К сожалению невозможно охватить все сразу. Да, для описания удобного кручения иммутабельного состояния ушла целая статья, про это собственно я и хотел написать, но возможно стоило уделить внимание и тем вопросам что вы озвучили. Думаю в будущем будет продолжение, а пока с остальным функционалам можно ознакомиться в репозитории https://github.com/simmor-store/simmor
удалено
Вот вам пожалуйста, посмотрите как можно использовать MobX и выкиньте то, что вы тут написали из головы, не дай god кому-то потом придется работать с кодом который вы написали:
codesandbox.io/s/goofy-hamilton-b9jxv — Быстрое знакомство с MobX, все самое основное, в том числе асинхронщина.
codesandbox.io/s/frosty-dust-2mk5b — Эффективный рендер (более продвинутый точечный рендер с вложонстью) MobX vs Redux.
codesandbox.io/s/adoring-kare-pre3r — MobX 4 (если нужна поддежка IE) Эффективный рендер (более продвинутый точечный рендер с вложонстью) MobX vs Redux.
codesandbox.io/s/silent-tdd-o1x69 — reaction, autorun, computed.
codesandbox.io/s/pedantic-silence-xu0jd — Переиспользование логики, и добавление useEffect в классовые компоненты (аналог reactjs.org/docs/hooks-custom.html)
codesandbox.io/s/priceless-sun-wr5dx — (голый React) Переиспользование логики, и добавление useEffect в классовые компоненты (аналог reactjs.org/docs/hooks-custom.html)
codesandbox.io/s/boring-lake-wspo3 — голый React хуки на классах
Примеры с использованием функциональных компонентов:
codesandbox.io/s/gallant-mountain-3w6bc — Пример с функциональными компонентами используя хуки
codesandbox.io/s/cocky-euler-x9b6e — Context with MobX 2х сторонний обмен данными и оптимизированный рендер (из коробки MobX), без дополнительных memo
codesandbox.io/s/flamboyant-mclean-tzjfp — Не кривое замыкание в функциональных компонентах
Наглядный пример мутабильность vs иммутабильность (когда в деле объекты, а не примитивы):
codesandbox.io/s/vibrant-leftpad-jc56q — смотреть в консоль, рендер каких компонентов вызывается
codesandbox.io/s/upbeat-flower-v0455 — Мультиязычность простой и реактивный вариант имплементации
akita смотрели? местами похоже на ваш подход
В redux проблему бойлерплейта (а как я понял с ним автор и борется) легко можно решит библиотекой от самих же создателей redux redux-toolkit, которая под капотом как раз использует Immer, позволяя в редьюсерах работать как-бы в mutable way
Вот пример
const counterSlice = createSlice({
name: 'counter',
initialState: 0,
reducers: {
increment: state => state + 1,
decrement: state => state - 1
}
})
const store = configureStore({
reducer: counterSlice.reducer
})
document.getElementById('increment').addEventListener('click', () => {
store.dispatch(counterSlice.actions.increment())
})
Управление состоянием приложения с RxJS/Immer как простая альтернатива Redux/MobX