51

Redux框架使用reducer来更改应用程序状态以响应操作。

关键要求是reducer 不能修改现有的状态对象;它必须产生一个新对象。

不好的例子

import {
    ACTIVATE_LOCATION
} from './actions';

export let ui = (state = [], action) => {
    switch (action.type) {
        case ACTIVATE_LOCATION:
            state.activeLocationId = action.id;
            break;
    }

    return state;
};

好例子

import {
    ACTIVATE_LOCATION
} from './actions';

export let ui = (state = [], action) => {
    switch (action.type) {
        case ACTIVATE_LOCATION:
            state = Object.assign({}, state, {
                activeLocationId: action.id
            });
            break;
    }

    return state;
};

这是Immutable.js的一个很好的用例。

4

5 回答 5

48

以 Immutable 为例

import {
    ACTIVATE_LOCATION
} from './actions';

import { Map } from 'immutable';

const initialState = Map({})

export let ui = (state = initialState, action) => {
  switch (action.type) {
    case ACTIVATE_LOCATION:
      return state.set('activeLocationId', action.id);
    default:
      return state;
  }
};
于 2015-08-09T00:25:45.233 回答
25

Immutable.js 应该根据需要在每个 reducer 中使用,例如

import {
    ACTIVATE_LOCATION
} from './actions';

import Immutable from 'immutable';

export let ui = (state, action) => {
    switch (action.type) {
        case ACTIVATE_LOCATION:
            state = Immutable
                .fromJS(state)
                .set('activeLocationId', action.id)
                .toJS();
            break;
    }

    return state;
};

但是,这个例子有很多开销:每次调用 reducer 动作时,它都必须将 JavaScript 对象转换为 Immutable 的实例,对结果对象进行变异并将其转换回 JavaScript 对象。

更好的方法是让初始状态成为 Immutable 的实例:

import {
    ACTIVATE_LOCATION
} from './actions';

import Immutable from 'immutable';

let initialState = Immutable.Map([]);

export let ui = (state = initialState, action) => {
    switch (action.type) {
        case ACTIVATE_LOCATION:
            state = state.set('activeLocationId', action.id);
            break;
    }

    return state;
};

这样,您只需要将初始状态转换为Immutableounce 的实例。然后每个 reducer 将其视为 的实例,Immutable并将其作为 的实例向下传递Immutable。问题是现在您需要在将值传递给视图上下文之前将整个状态转换为 JavaScript。

如果您在 reducer 中执行多个状态突变,您可能需要考虑使用.withMutations.

为了让事情更简单,我开发了一个redux-immutable库。它提供combineReducers的功能等同于 redux 包中的同名功能,只是它期望初始状态和所有 reducer 都与Immutable.js对象一起工作。

于 2015-08-08T11:44:25.963 回答
8

如果您只是在寻找一种简单的方法来进行无突变的更新,我维护了一个库:https ://github.com/substantial/updeep ,在我看来,这是使用redux.

updeep允许您使用常规(冻结)对象层次结构,因此您可以进行解构、查看日志和调试器中的对象等。它还具有允许批量更新的强大 API。对于大型数据集,它不会像 Immutable.js 那样高效,因为它会在需要时克隆对象。

这是一个示例(但请查看自述文件中的更多内容):

import {
    ACTIVATE_LOCATION
} from './actions';
import u from 'updeep';

export let ui = (state = [], action) => {
    switch (action.type) {
        case ACTIVATE_LOCATION:
            state = u({ activeLocation: action.id }, state);
            break;
    }

    return state;
};
于 2015-08-08T17:25:02.950 回答
5

接受的答案不应该是接受的答案。您需要使用 immutable 初始化状态,然后(如前所述)使用 redux-immutablejs

const initialState = Immutable.fromJS({}) // or Immutable.Map({})

const store = _createStore(reducers, initialState, compose(
    applyMiddleware(...middleware),
    window.devToolsExtension ? window.devToolsExtension() : f => f
));

比使用 redux-immutablejs 中的 combineReducers

额外提示:使用 react-router-redux 效果很好,所以如果你想添加这个,然后用这个替换 react-router-redux 中的 reducer:

import Immutable from 'immutable';
import {
    UPDATE_LOCATION
} from 'react-router-redux';

let initialState;

initialState = Immutable.fromJS({
    location: undefined
});

export default (state = initialState, action) => {
    if (action.type === UPDATE_LOCATION) {
        return state.merge({
            location: action.payload
        });
    }

    return state;
};

只需将其导入您的根减速器

这在 redux-immutablejs 的文档中也有说明

于 2016-02-11T01:39:12.977 回答
2

看看https://github.com/indexiatech/redux-immutablejs

它几乎是一个符合 Redux 标准combineReducer的可选项。createReducer

于 2015-09-04T15:38:42.333 回答