如何在REDx中使用Immutable.js?

Gaj*_*jus 50 javascript immutable.js redux

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

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

不好的例子:

import {
    ACTIVATE_LOCATION
} from './actions';

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

    return state;
};
Run Code Online (Sandbox Code Playgroud)

好例子:

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;
};
Run Code Online (Sandbox Code Playgroud)

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

Geo*_*lah 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;
  }
};
Run Code Online (Sandbox Code Playgroud)

  • 你能详细说明为什么你认为这种方法不能与combineReducers一起使用吗?我已经测试了这个,据我所知(也通过阅读你链接的combineReducers的代码) - 不应该有任何阻止它工作的东西. (3认同)
  • 我可以证实.当整个状态实际上是Immutable.Map时,即使Redux高于3.x,它也不起作用.一个如果它的键可以是Immutable.Map,但不是状态本身. (3认同)
  • @dakt我已经更新了`redux-immutable`实现来解决这个特定的问题而没有其它副作用,https://github.com/gajus/redux-immutable#problem. (2认同)

Gaj*_*jus 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;
};
Run Code Online (Sandbox Code Playgroud)

但是,在这个例子中有很多开销:每次调用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;
};
Run Code Online (Sandbox Code Playgroud)

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

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

为了简化操作,我开发了一个redux-immutable库.它提供的combineReducers函数等同于redux包中同名函数的功能,除了它期望初始状态和所有reducers与Immutable.js对象一起使用.

  • 状态不应该包含对不可变对象的引用吗?使用Immutable将对象转换为Immuttable然后返回到对象似乎失去了Immutable的一些好处.例如,能够对Immutable对象进行未来的更改,其中Immutable.js库将为您有效地进行这些更改.思考? (3认同)

Aar*_*sen 8

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

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

这是一个例子(但请查看README中的更多内容):

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;
};
Run Code Online (Sandbox Code Playgroud)


小智 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
));
Run Code Online (Sandbox Code Playgroud)

比使用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;
};
Run Code Online (Sandbox Code Playgroud)

只需将其导入根减速器即可

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