Изменение состояния одного компонента в отдельном редукторе влияет на состояние другого редуктора? - PullRequest
0 голосов
/ 08 апреля 2020

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

У меня также есть другой компонент с некоторыми другими настройками, который называется Inputs, данные для него - это просто массив настроек. У меня также есть распознаватель, который находится на переходе к этому компоненту, поэтому он должен иметь один, но есть фильтр для распознавателя, который гарантирует, что массив не пуст.

Это прекрасно работает, пока не произойдет изменение настроек устройства. Когда есть изменение, массив, который исходит от селектора в редукторе компонента Inputs, становится пустым на пару секунд, а затем снова заполняется нормальными значениями (я отображаю это, регистрируясь на консоли селектора, который выбирает все элементы из этого состояния). Это создает проблему, потому что я могу либо обойти фильтр, который помещает меня на страницу, когда она пуста и выглядит неработающей, пока значения не заполнены, или моя навигация застревает в преобразователе, потому что Observable иногда не получает непустой массив.

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

Редуктор 1:

export interface DeviceSettingsState {
  device: DeviceSettings;
  systemTime: SystemDateTime;
}
...
export const initialDeviceState: DeviceSettings = undefined;
export const initialSystemTimeState: SystemDateTime = undefined;

// Update success is the problem
export function deviceReducer(
  state: DeviceSettings = initialDeviceState,
  action: DeviceSettingsActionUnion
): DeviceSettings {
  switch (action.type) {
    case DeviceSettingsActionTypes.LoadSuccess:
      return <DeviceSettings>action.payload;
    case DeviceSettingsActionTypes.UpdateSuccess:
      return { ...state, ...action.payload };
    default:
      return state;
  }
}

Редуктор 2 :

// Internal Object is just an object with a bunch of fields. The state in this case is a list of those objects
export interface InternalObjectEntityState extends EntityState<InternalObject> {
  mode: number;
}

const adapter: EntityAdapter<InternalObject> = createEntityAdapter<InternalObject>({
  selectId: selectUniqueInternalObject,
  sortComparer: sortByInstanceAndObjectType
});

const initialSate: InternalObjectEntityState = adapter.getInitialState({
  mode: 0
});

export function internalObjectsReducer(
  state: InternalObjectEntityState = initialSate,
  action: InternalObjectsActionUnion
): InternalObjectEntityState {
  switch (action.type) {
    case InternalObjectsActionTypes.LoadSuccess:
      return adapter.addAll(action.payload, state);
    // 25 Mar 2020 Onur, Handling the UpdateMode action type
    case InternalObjectsActionTypes.UpdateMode:
      // 08 Apr 2020 Onur, proper way to update state
      return { ...state, mode: action.payload };
    default:
      return state;
  }
}

// And below is the selector that yields empty state when an update on the other reducer happens
export const selectInternalObjectEntityState = (state: AppState) => state.internalObjectState;

export const {
  selectIds: selectObjIds,
  selectEntities: selectObjEntities,
  selectAll: selectAllObjs
} = adapter.getSelectors(selectInternalObjectEntityState);

export const selectCurrentMode = createSelector(
  selectInternalObjectEntityState,
  (state: InternalObjectEntityState) => state.mode
);

// This one
export const selectAnalogAndBinaryInputsForMode = createSelector(
  selectAllObjs,
  selectCurrentMode,
  (state: InternalObject[], mode: number) => {
    // Console loggging state here gives an array of items mostly, when there is a change on the other reducer, it becomes empty for a bit
    return state.filter(
      obj =>
        (obj.objectType === BACnetObjectType.analogInput ||
          obj.objectType === BACnetObjectType.binaryInput) &&
        getIndex(obj, mode)
    );
  }
);
...

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

Кстати, это не мой код, это код, который был там, когда я присоединился к компании.

Подключение редуктора 1 к модулю:

...
imports: [
    SharedModule,
    StoreModule.forFeature('device', deviceReducerMap),
    EffectsModule.forFeature([DeviceSettingsEffects])
  ],
...

Подключение редуктора 2

app / store / redurs / index.ts:

...
// The interface of the AppState
export interface AppState {
  internalObjectState: InternalObjectEntityState;
}

// A map of all the reducers
export const reducers: ActionReducerMap<AppState> = {
  internalObjectState: internalObjectsReducer
};

app .module.ts:

...
StoreModule.forRoot<AppState>(reducers, {
      metaReducers,
      runtimeChecks: {
        strictStateImmutability: true,
        strictActionImmutability: true,
        strictStateSerializability: true,
        strictActionSerializability: true
      }
    }),
    EffectsModule.forRoot(appEffects),
...

Надеюсь, это поможет

1 Ответ

0 голосов
/ 08 апреля 2020

Если честно, трудно точно понять, в чем дело, и фрагмент кода был бы полезен.

Вместо того, чтобы обрабатывать одно и то же действие в разных редукторах, вы можете использовать ngrx / Effects с эффектом, который создает 2. действия, по одному для каждого редуктора, чтобы их контексты не смешивались.

Если вы хотите пропустить недопустимые значения (эти 2 секунды), вы можете добавить оператор filter сразу после select, что-то вроде filter(v => !!v) для ложные значения и filter(v => v.length > 0) для пустых массивов.

...