【问题标题】:Pattern for managing multiple reducers inside of a module [Redux]用于管理模块内的多个 reducer 的模式 [Redux]
【发布时间】:2016-08-16 17:44:43
【问题描述】:

我是 Redux 的新手,正在尝试找出一种可扩展的方式来设置我的项目文件夹/文件结构。

假设我们有一个如下所示的文件结构:

root/modules/Todos/reducers

在项目的根目录中有一个“rootReducer.js”文件,它利用“combineReducers()”创建状态树的顶级实现:

[rootReducer.js]

import { combineReducers } from 'redux';

import todos from './modules/Todos/reducers/index.js';

export default combineReducers({
  todos: todos
});

在每个模块的“reducers”文件夹中都有多个reducer:

[root/modules/Todos/reducers]

>index.js
>Todos__addItem
>Todos__removeItem

'index.js' 文件导入该模块的所有 reducer 并导出单个对象:

[index.js]

import { combineReducers } from 'redux';

import addItem from './Todos__addItem.js';
import removeItem from './Todos__removeItem.js';

export default const todos = combineReducers({
  addItem: addItem,
  removeItem: removeItem
});

这是“combineReducers()”的正确用法吗?

这种模式在开发大型应用程序时有意义吗?

这种模式有哪些(如果有的话)潜在陷阱?

谢谢!

【问题讨论】:

标签: reactjs directory redux file-structure directory-structure


【解决方案1】:

这绝对不是combineReducers 的正确用法。 combineReducers 用于将特定状态片的管理委托给给定函数。您的示例实际上会创建名为 addItem 和 removeItem 的状态切片,而您真正想要做的是根据分派的操作以不同的方式使用这些函数更新相同的 todos 状态切片。

"Structuring Reducers" 上的 Redux 文档部分提供了一些有助于解决此问题的信息,包括Using combineReducers 上的部分。

【讨论】:

  • 感谢您对您的作品所做的回复和工作!关于 'index.js' 中的 'export todos' 语句,你知道我可以如何重构它来实现我想要的吗?我在找出实现它的正确方法时遇到了麻烦!我应该将子归约器的集合导出为一个函数,还是只是一个普通对象?
  • todo 处理将是您看到各种更新案例的典型 switch 语句或查找表的地方。有关相关示例,请参阅redux.js.org/docs/recipes/…。此外,如果您还没有看过它们,Dan 有两个很棒的视频教程系列,他演示了许多 reducer 方法:egghead.io/series/getting-started-with-redux 和 egghead.io/series/…。
【解决方案2】:

来自https://github.com/suin/redux-multiple-reducers-example的示例

import   {counter1, counter2 } from "../../reducers/index"
import CounterApp from "../containers/CounterApp";


const rootReducer = combineReducers({
  one:counter1 ,
  two:counter2
});

const store = createStore(rootReducer);

class App extends  React.Component{
  render() {
    return (
      <Provider store={store}>
          <CounterApp />
      </Provider>
    );
  }

柜台1视图

import * as counter1Actions from "../../actions/counter1Actions";

@connect(state => ({
  counter1: state.one
}))
export default class Counter1 extends  React.Component{

  static propTypes = {
    counter1: PropTypes.number.isRequired
  }

  componentDidMount() {
    console.info("counter1 component did mount.");
  }

  onClick() {
    console.info("counter1 button was clicked.");
    const action = bindActionCreators(counter1Actions, this.props.dispatch);
    action.increment();
  }

  render() {
    return (
      <div>
        <h1>Counter 1</h1>
        <button onClick={::this.onClick}>increment</button>
        <div>Total: <span>{this.props.counter1}</span></div>
      </div>
    );
  }
}

柜台2视图

import * as counter2Actions from "../../actions/counter2Actions";

@connect(state => ({
  counter2: state.two
}))
export default class Counter2 extends  React.Component {
  static propTypes = {
    counter2: PropTypes.number.isRequired
  }

  componentDidMount() {
    console.info("counter2 component did mount.");
  }

  onClick() {
    console.info("counter2 button was clicked.");
    const action = bindActionCreators(counter2Actions, this.props.dispatch);
    action.increment();
  }

  render() {
    return (
      <div>
        <h1>Counter 2</h1>
        <button onClick={::this.onClick}>increment</button>
        <div>Total: <span>{this.props.counter2}</span></div>
      </div>
    );
  }
}

CounterApp

import Counter1 from "../components/Counter1";
import Counter2 from "../components/Counter2";

 class CounterApp extends  React.Component{
   render() {
     return (
       <div>
         <Counter1/>
         <Counter2/>
       </div>
     );
   }
 }

减速器

export default function counter1(state = initialState, event) {
  switch (event.type) {
    case "COUNTER1_INCREMENTED":
      console.info(`counter1 ack ${event.type}: event =`, event);
      return state + 1;
    default:
      console.warn("counter1 ack unknown event: state =", state, "event =", event);
      return state;
  }

export default function counter2(state: Object = initialState, event: Object): Object {
  switch (event.type) {
    case "COUNTER2_INCREMENTED":
      console.info(`counter2 ack ${event.type}: event =`, event);
      return state + 1;
    default:
      console.warn("counter2 ack unknown event: state =", state, "event =", event);
      return state;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    • 2018-01-03
    相关资源
    最近更新 更多