使用 Redux 如何阻止 reducer 中的 switch 增长?

Posted

技术标签:

【中文标题】使用 Redux 如何阻止 reducer 中的 switch 增长?【英文标题】:Using Redux how do you stop the switch in the reducer growing? 【发布时间】:2018-08-05 08:08:42 【问题描述】:

我正在使用 Angular 5 和 ng2-Redux。

我正在使用减速器和开关,但我担心开关会随着我添加更多动作类型而增长。

目前我正在尝试使用红色组合减速器来管理状态和文件的增长:

我目前收到此错误:

未处理的 Promise 拒绝:Reducer "app" 在期间返回未定义 初始化。如果传递给减速器的状态是未定义的,你 必须显式返回初始状态。初始状态可能不是 不明确的。如果你不想为这个 reducer 设置一个值,你可以 使用 null 而不是 undefined。 ;区:;任务:Promise.then ; 值:错误:Reducer“app”在初始化期间返回未定义。 如果传递给减速器的状态未定义,则必须显式 返回初始状态。初始状态可能不是未定义的。如果 您不想为此减速器设置值,可以使用 null 而不是未定义。

似乎 rootReducer 需要返回状态,但我使用的是组合减速器。

我的减速机服务代码:

import  combineReducers  from 'redux';

export interface IAppState 
    counter?: number;
    user?: Object;
    numberOfMessages?: number;


export interface IAction 
    type: string;
    payload?: any;


export const INITIAL_APP_STATE: IAppState = 
    counter: 0,
    user: ,
    numberOfMessages: 0
;

export const appReducer = (state: IAppState, action: IAction): IAppState => 
    switch (action.type) 
        case 'INCREMENT':
        return  
            counter: state.counter + action.payload,
            numberOfMessages: state.numberOfMessages
        ;
    
    return state;
;

export const userReducer = (state: IAppState, action: IAction): IAppState => 
    switch (action.type) 
        case 'DECREMENT':
        return  
            counter: state.counter,
            numberOfMessages: state.numberOfMessages - action.payload
        ;
    
    return state;
;

export const rootReducer = combineReducers(
  app: appReducer,
  user: userReducer
);

这是我用于 redux 设置的模块导出部分(我认为这里有错误????):

export class AppModule 
  constructor(ngRedux: NgRedux<IAppState>) 
    ngRedux.configureStore(rootReducer, INITIAL_APP_STATE);
  

这是我的调度方法:

 public increment(): void 
    this.ngRedux.dispatch(
      type: '[app] INCREMENT',
      payload: 1
    );
  

 public decrement(): void 
    this.ngRedux.dispatch(
      type: '[user] DECREMENT',
      payload: 2
    );
  

【问题讨论】:

你可以在关于这个主题的另一个问题中找到答案。***.com/questions/48950721/… @Ricardo 我目前无法将 rootReducer 连接到 app 模块中的配置,这是一个 combineReducer。见上文 【参考方案1】:

您应该将您的 IAppState 拆分为不同的功能状态:

export interface IAppState = 
  auth: IAuthState;
  onboarding: IOnboardingState;
  feedback: IFeedbackState;
;

然后您使用来自'redux'combineReducers 从所有功能缩减器中构建您的rootReducer

export const rootReducer = combineReducers(
  auth: authReducer,
  onboarding: onboardingReducer,
  feedback: feedbackReducer
);

因此,您的功能状态、操作、reducer 和史诗将更小且更易于维护。

您可以在操作名称中添加特定于功能的前缀,以确保它们是唯一的:

export class CounterActions 
  static INCREMENT: string = '[COUNTER] INCREMENT';
  static DECREMENT: string = '[COUNTER] DECREMENT';
  static RANDOMIZE: string = '[COUNTER] RANDOMIZE';

更新:您的后续问题

解决方法在错误信息中,仔细阅读:

如果传递给reducer的状态是未定义的,你必须明确 返回初始状态。

需要传入初始状态作为默认值:

export const userReducer = (state: IUserState = INITIAL_USER_STATE, action: IAction): IAppState => 
                                   ^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^
    switch (action.type) 
        case 'LOGIN':
        return  
            userName: action.payload.userName
        ;
    
    return state;
;

另外,userReducer 只获取传入状态的IUserState 切片。

【讨论】:

现在如何使用这三个减速器中的哪一个? 您的动作名称必须是唯一的,因为它们仍将通过所有减速器。您可以通过为所有操作添加特定于功能的前缀来实现这一点。 根据您的用例,分形存储可能是您的选择。看看github.com/angular-redux/store/blob/master/articles/… 你能给我看一个上面的动作前缀示例,以便调用特定的减速器 我已经编辑了我的答案 ;-) 由于您的操作的独特性,正确的功能缩减程序将更新您的商店。

以上是关于使用 Redux 如何阻止 reducer 中的 switch 增长?的主要内容,如果未能解决你的问题,请参考以下文章

在 Redux 中,如果所有 reducer 在动作触发时都被调用,那么是啥阻止了动作之间可能的命名冲突?

如何在reducer中专门使用redux来获取react-native中的API?

如何使用 redux-toolkit 中的 createSlice 方法在不同的 reducer 函数中使用单个动作类型

如何重用 Redux Toolkit createSlice 函数中的 reducer 逻辑?

redux 中的 action、reducer 和 store 有啥区别?

如何渲染存储在 redux reducer 中的 reactjs 组件?