Предоставление корневого редуктора в @ ngrx / store 4.0

В @ ngrx / store 2.0 мы могли предоставить корневой редуктор как функцию, и оттуда мы разделили нашу логику внутри приложения. После обновления до @ ngrx / store 4.0 я больше не могу использовать эту функцию из того, что я вижу, редукторы должны быть картой редукторов, которые будут создавать объекты с теми же ключами в состоянии. Есть ли способ использовать старое поведение в @ ngrx / store 4.0? В моих компонентах состояния известно друг о друге, и мне нужно иметь возможность динамически разбивать свое состояние, также мне нужно иметь возможность отправлять действия на правильный редуктор в моем собственный путь. Также приложение разделено на несколько маршрутов с отложенной загрузкой, которые в некоторых случаях повторно используют данные из другой функции.

 StoreModule.provideStore(reducer, {
      auth: {
        loggedIn: true
      }
    })

StoreModule.forRoot(reducers, {
      initialState: {
        auth: {
          loggedIn: true
        }
      }
    })

Мне нужно, чтобы reducers была функцией, которая получает полное состояние и отправляет его правильному редуктору. Есть ли способ добиться такого поведения?


person Nicu    schedule 20.07.2017    source источник


Ответы (4)


После второго просмотра репозитория ngrx я понял это. Для достижения желаемого результата нам нужно заменить фабрику редукторов @ ngrx / store новой реализацией. Я ввел новую фабрику редукторов, и сейчас приложение работает как раньше. Простой пример кода о том, как заменить редуктор factory it.

// This factory replaces @ngrx combine reducers so we can manage how we split the keys inside the state
export function combineReducersFactory(
    reducers: any,
    initialState: any = {}
): ActionReducer<any, Action> {
    return function combination(state = initialState, action) {
        const nextState: any = reducers(state, action);
        return nextState !== state ? nextState : state;
    };
}

export const NG_RX_STORE_PROVIDER = [
    StoreModule.forRoot(rootReducer, createEmptyState()),
];

export const NG_RX_REDUCER_FACTORY = [
    {
        provide: REDUCER_FACTORY,
        useFactory: () => combineReducersFactory
    }
];

@NgModule({
    imports: [
        ...NG_RX_STORE_PROVIDER
    ],
    declarations: [...APP_COMPONENTS, ...AG_GRID_COMPONENTS],
    providers: [...NG_RX_REDUCER_FACTORY]
})
export class AppModule {
}
person Nicu    schedule 21.07.2017

Вы можете настроить мета-редуктор получать каждое событие и управлять состоянием из его корня. Вот пример его настройки:

const myInitialState = {
  // whatever you want your initial state to be
};

export function myMetaReducer(
  reducer: ActionReducer<RootStateType>
): ActionReducer<RootStateType> {
  return function(state, action) {
    if (iWantToHandleThisAction) {
      state = doWhatIWantWith(state);
    }
    return reducer(state, action);
  };
}

@NgModule({
  imports: [
    StoreModule.forRoot(myInitialState, { metaReducers: [myMetaReducer] })
  ]
})
export class AppModule {}
person Eric Simonton    schedule 05.10.2017
comment
myInitialState не определен и неверный параметр наверняка - person ntaso; 20.11.2017
comment
Замени myInitialState на {}, и тогда все заработает. Это параметр не в исходном состоянии, а в ActionReducerMap. Поскольку в этом сценарии ничего не отображается и все обрабатывается метаредуктором, он работает. - person ntaso; 20.11.2017
comment
Извините - я хотел, чтобы это было заполнителем для всего, что вы хотите передать в качестве исходного состояния - отредактирую, чтобы сделать это более понятным. - person Eric Simonton; 20.11.2017

Функция StoreModule forRoot() принимает reducerFactory, который можно использовать следующим образом:

export function myReducerFactory(reducers: any, initState: any) {
  return (state = myInitialState, action) => myCustomReducer(state, action);
}

@NgModule({
  // ...
  imports: [
    StoreModule.forRoot(null, { reducerFactory: myReducerFactory })
  ]
  // ...
})
export class AppModule {
}
person Stephen Paul    schedule 30.04.2018

Это работает для меня:

// your old reducer that handled slicing and dicing the state
export function mainReducer(state = {}, action: Action) {
    // ...
    return newState;
}

// new: metaReducer that just calls the main reducer
export function metaReducer(reducer: ActionReducer<AppState>): ActionReducer<AppState> {
    return function (state, action) {
        return MainReducer(state, action);
    };
}

// new: MetaReducer for StoreModule.forRoot()
export const metaReducers: MetaReducer<any>[] = [metaReducer];

// modified: app.module.ts
@NgModule({
    // ...
    imports: [
        // neglect first parameter ActionReducerMap, we don't need this
        StoreModule.forRoot({}, {
            metaReducers: metaReducers,
            initialState: INITIAL_STATE // optional
        }),
    ]
})
person ntaso    schedule 20.11.2017