如何在REDx中使用Immutable.js?

时间:2015-08-08 11:44:26

标签: 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;
};

好例子

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的一个很好的用例。

5 个答案:

答案 0 :(得分: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;
  }
};

答案 1 :(得分: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;
};

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

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

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

答案 2 :(得分: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;
};

答案 3 :(得分: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

的文档中说明了这一点

答案 4 :(得分:2)

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

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