Почему я могу изменить состояние, изменив объект, полученный от селектора? - PullRequest
1 голос
/ 17 октября 2019

Читая документацию по ngrx, я понял, что для модификации хранилища используются только редукторы. Однако во время кодирования я заметил, что если я изменю любое поле в объекте, возвращаемом селектором, изменение будет применено к хранилищу. Я предполагаю, что получаю оригинальный объект из селектора.

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

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

Я добавляю пример кода:

Состояние:

export interface IAppState {
    offersList: IOffer[],
}

Действия:

export enum OffersActions {
    Get = '[Offer] Get',
    GetSuccess = '[Offer] GetSuccess'
}

export const getOffers = createAction(
    OffersActions .Get,
);

export const getOffersSuccess = createAction(
    GetSuccess .GetSuccess,
    props<{offersList: IOffer[]}>()
);

Редукторы:

export const offersReducer = createReducer(
    [],
    on(OffersActions.getOffersSuccess, (state, offers) => (offers.offersList))
);

Эффекты:

getOffers$ = createEffect(() => this.actions$.pipe(
    ofType(getOffers),
    mergeMap(() => this.offersService.SearchMany().pipe(
        map(res => ({
            type: OffersActions.GetSuccess,
            offersList: res
        }))
    ))
));

Селекторы:

const offers = (state: IAppState) => state.offersList;

export const selectOffers = createSelector(
    offers ,
    (state: IOffers[]) => state
);

export const selectOfferById = (id) => createSelector(
    offer,
    (state: IOffer[]) => state.find(x => x.id == id)
)

Использование (внутри компонента):

this.offer$ = this.store
        .pipe(select(selectOfferById(this.route.snapshot.params.id)));

<offer-form
    [offer]="offer$ | async">
</offer-form>

И теперь, если я изменю предложение внутри OfferFormComponent (например, внутри ввода), изменение применяется к магазину.

Также еще два вопроса:

Я добавил metaReducer storeFreeze из ngrx-store-freeze. Теперь я вижу, что объект, возвращаемый селектором, нельзя изменить - изменения во входных данных не применяются ни к объекту, ни к хранилищу.

  1. В storeFreeze README есть:

При возникновении мутации будет выдано исключение.

Почему я нев моей консоли нет исключений?

Я хочу выбрать какую-то часть магазина и поместить восстановленный объект в форму. Я хочу применить все изменения, чтобы сохранить, только если пользователь нажмет кнопку отправки. Таким образом, единственный способ сделать это - подписаться на выделение, скопировать результат, изменить клонированный объект и затем использовать редуктор? Например, вот так:

this.offers $ .subscribe (x => this.offers = JSON.parse (JSON.stringify (x)));

1 Ответ

1 голос
/ 17 октября 2019

Это на вас "клонировать" объект в редуктор. Поскольку вы знаете, что изменилось, если мы клонируем весь магазин, это будет ударом по производительности. Другой вариант - использовать immer, что делает это за вас:

NgRx использует только ссылкупроверки (===), которые являются производительными.

Если вы используете NgRx 8, вы можете использовать проверки во время выполнения , если не можете использовать store-freeze metareducer, чтобы поймать эти мутации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...