用于管理模块内多个Reducer的模式[Redux]

问题描述 投票:1回答:2

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

让我们说我们有一个如下所示的文件结构:

根/模块/托多斯/减速

在项目的根目录中存在一个'rootReducer.js'文件,它使用'combineReducers()'来创建状态树的顶级实现:

[rootReducer.js]

import { combineReducers } from 'redux';

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

export default combineReducers({
  todos: todos
});

每个模块的'redurs'文件夹内有多个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
2个回答
2
投票

这绝对不是combineReducers的正确用法。 combineReducers用于将特定状态切片的管理委托给给定函数。您的示例实际上会创建名为addItemremoveItem的状态切片,当您真正想要做的是根据调度的动作以不同方式更新相同的todos状态切片。

我实际上正在为Redux文档编写一个关于“构建减速器”主题的新部分。您可能想要阅读当前的WIP草案 - 其中一些可能有所帮助。该草案可在https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md获得。一些示例应与您的问题相关。


0
投票

来自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>
    );
  }

Counter1视图

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>
    );
  }
}

Counter2观点

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;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.