Комментарии 17
export class FeedZebra {
static readonly type = '[Zoo] FeedZebra';
constructor(public zebraToFeed: ZebraFood) {}
}
...
@Action(FeedZebra)
feedZebra(ctx: StateContext<ZooStateModel>, action: FeedZebra) {
const state = ctx.getState();
ctx.patchState({
zebraFood: [
...state.zebraFood,
action.zebraToFeed,
]
});
}
И это всё нужно для того, чтобы запушить значение в массив? На Mobx будет так:
@action
feedZebra(zebraToFeed: ZebraFood) {
this.zebraFood.push(zebraToFeed)
}
Mobx в каждом observable значении (в нашем случае zebraFood) хранит список слушателей, которые будут отработать при изменении этого значения. Слушателями будут выступать компоненты, которые рендерят этот observable. На выходе очень малое количество кода и прозрачный принцип работы. Чуть более подробно о недостатках Redux-подобных сторов, писал тут: habr.com/ru/company/inobitec/blog/481288/#comment_21052464
Конечно, не для того, чтобы запушить в массив. Redux-подобные сторы реализуют паттерн CQRS, с четким разделением запросов и команд. Обработка action-а может быть сколь угодно нетривиальной. У меня, например, был проект, где фронтенд взаимодействовал с rest api и двумя websocket api, без централизованного стейта и потока actions-reducers это бы все легко превратилось в один большой race condition. И возможность просто "отреплеить" экшены очень пригодилась (в первом приближении это что-то похожее на реплей стрима на youtube вместе с чатом). Там, правда, был ngrx (ngxs тогда еще не было, да и ngrx только появился); ngxs, мне кажется, более естественно вписывается в angular.
Для простых проектов согласен, что mobx уместнее — там добавляемая CQRS сложность не "окупится". Хотя к этой магии с обертками у меня личная неприязнь со времен knockout, но это субъективное :-)
Речь не о размере, а о сложности взаимодействий, модель-то там была относительно небольшая.
Впрочем, большие модели — это повод разделить их по разным bounded context. Большая модель, где все со всем жестко связано — это как ни крути ад получится.
Спасибо за статью, но на мой взгляд, отсутствие примеров с кодом не делает это введение понятнее.
import { BehaviorSubject, Observable } from 'rxjs';
export function observable() {
return <T>(target: any, propertyName: string) => {
Object.defineProperty(target.constructor.prototype, `${propertyName}$`, {
get(): Observable<T> {
if (!this[`$$_${propertyName}`]) {
this[`$$_${propertyName}`] = new BehaviorSubject(undefined);
}
if (!this[`$$_${propertyName}$`]) {
this[`$$_${propertyName}$`] = this[`$$_${propertyName}`].asObservable();
}
return this[`$$_${propertyName}$`];
}
});
Object.defineProperty(target.constructor.prototype, propertyName, {
get(): T {
return this[`$$_${propertyName}$`].source.getValue();
},
set(value: T) {
if (this[`${propertyName}$`]) {
this[`$$_${propertyName}`].next(value);
}
}
});
};
}
После чего получить стейт
@Injectable()
class AppState {
userId$: Observable<number>;
@observable()
userId: number;
}
Затем в компонентах можно просто слушать как обычный Observable
Angular: понятное введение в NGRX