在现有应用程序中实现`combineReducers`的规范方法

时间:2018-02-09 21:29:40

标签: javascript reactjs redux react-redux reducers

我有一个redux存储,到现在为止它已经非常复杂,只需要一个reducers文件。但是我现在需要拆分它。使用combineReducers{reducerOne, reducerTwo}是我必须重构我的应用以进入以下实例的方式:

const mapStateToProps = state => ({
  prop1: state.prop1,
  /*...many more...*/
})

并将其更改为:

const mapStateToProps = state => ({
  prop1: state.reducerOne.prop1,
  /*...many more...*/
})

还是有更规范的方式?如果我摆脱了隐含的回报并使第一行state = state.reducerOne或其他东西,它可能会缩短一点。

是否有更好/更规范的方法来合并新命名的reducer?

2 个答案:

答案 0 :(得分:3)

看看这些事情:

使用这些工具和方法,你最终会成功 从您的Reducer导出的通用选择器, (正在解决那些减速器负责的子国家的通用数据) 然后导入rootReducer 它们用来创建另一组通用选择器来解析相同的数据,但是来自州的根。

之后,基本上有两种概念上不同的方式:

  • 保持组件(我们称之为“容器”或“智能”组件)特定选择器 与容器组件本身一起(以下示例更多关于此特定情况)

  • 拥有一个单独的“数据层”,它对组件的了解不多,它将为其提供数据 并在那里保留面向数据/功能的选择器,使用您为项目定义的模式进行组织。

当然,你可以在某种程度上结合两者。 但重要的是找出边界并保留所有属于它们的东西。

<...>/FooContainer/selectors.js和你的一起 <...>/FooContainer/FooContainer.jsx组件。

reducers/entities.js

import { INITIAL_STATE } from 'initialState';

export default (state = INITIAL_STATE.entities, action) => {
  /* reducer */
};

export const getModelData = (entities, model, keyWindow) => {
  /*
   get model data from normalized entities store
   using model fields and the keyWindow
  */
};

reducers/index.js

// <...>

/* entities, location, contents - are reducers  */
import entities, * as fromEntities from './entities';
import location, * as fromLocation from './location';
import contents, * as fromContents from './contents';

// <...>

export const rootReducer = combineReducers({
  entities,
  location,
  contents,
});


const getEntities = state => state.entities;
const getLocation = state => state.location;
const getContents = state => state.contents;

// <...>

// this is a generic selector for getting the data from
// the entities store.
export const getModelData = createSelector(
  [getEntities, (state, model, keyWindow) => ({ model, keyWindow })],
  fromEntities.getModelData,
);

// ...

FooContainer/selectors.js

import { getModelData } from 'app/reducers';

export const componentData = createSelector(
  [getModelData, (state, model, keyWindow, props) => props],
  (modelData, props) => { /* do something specific for your component */},
);

FooContainer/FooContainer.jsx

import { componentData } from './selectors';
import { FooModel } from 'fooFeature/models';
import { someFooAction, loadFooData } from 'fooFeature/actions';

const getKeyWindow = props => {/* return keyWindow */ };
const mapStateToProps = (state, props) => ({
  componentData: componentData(state, FooModel, getKeyWindow(props), props),
});
const mapDispatchToProps = {
  someFooAction,
  loadFooData,
};

@connect(mapStateToProps, mapDispatchToProps)
class FooContainer extends Component {
  static propTypes = {
    componentData: PropTypes.arrayOf(PropTypes.object),
    loadFooData: PropTypes.func.isRequired,
    someFooAction: PropTypes.func.isRequired,
  }

  /* <...> */
}

答案 1 :(得分:0)

可能构建它:

const mapStateToProps = ({reducerOne}) => ({
  prop1: reducerOne.prop1,
  /*...many more...*/
})