简体   繁体   English

如何在REDx中使用Immutable.js?

[英]How to use Immutable.js with redux?

Redux framework is using reducers to change app state in response to an action. Redux框架使用reducers来更改应用程序状态以响应操作。

The key requirement is that a reducer cannot modify an existing state object; 关键要求是reducer不能修改现有的状态对象; it must produce a new object. 它必须产生一个新的对象。

Bad Example : 不好的例子

import {
    ACTIVATE_LOCATION
} from './actions';

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

    return state;
};

Good Example : 好例子

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

This is a good use case for Immutable.js . 这是Immutable.js的一个很好的用例。

Taking your good example with Immutable 以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;
  }
};

Immutable.js ought to be used in each reducer as needed, eg 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;
};

However, there is a lot of overhead in this example: every time reducer action is invoked, it has to convert JavaScript object to an an instance of Immutable, mutate the resulting object and convert it back to JavaScript object. 但是,在这个例子中有很多开销:每次调用reducer动作时,它都必须将JavaScript对象转换为Immutable实例,改变生成的对象并将其转换回JavaScript对象。

A better approach is to have the initial state an instance of Immutable: 更好的方法是让初始状态为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;
};

This way, you only need to convert the initial state to an instance of Immutable ounce. 这样,您只需要将初始状态转换为Immutable盎司的实例。 Then each reducer will treat it as an instance of Immutable and pass it down the line as an instance of Immutable . 然后,每个减速将会把它当作一个实例Immutable ,并将它传递的路线作为实例Immutable The catch is that now you need to cast the entire state to JavaScript before passing the values to the view context. 问题是,现在您需要在将值传递给视图上下文之前将整个状态转换为JavaScript。

If you are performing multiple state mutations in a reducer, you might want to consider batching mutations using .withMutations . 如果您在reducer中执行多个状态突变,您可能需要考虑使用.withMutations 批处理突变

To make things simpler, I have developed a redux-immutable library. 为了简化操作,我开发了一个redux-immutable库。 It provides combineReducers function thats equivalent to the function of the same name in the redux package, except that it expect the initial state and all reducers to work with Immutable.js object. 它提供了combineReducers函数,它等同于redux包中同名函数的功能,除了它期望初始状态和所有reducers与Immutable.js对象一起使用。

If you're just looking for an easy way to make updates without mutation, I maintain a library: https://github.com/substantial/updeep which, in my opinion, is a good way to do that with redux . 如果您只是在寻找一种简单的方法来进行更新而不会发生变异,我会维护一个库: https//github.com/substantial/updeep ,在我看来,这是使用redux实现这一目标的好方法。

updeep lets you work with regular (frozen) object hierarchies, so you can do destructuring, see objects in logs and the debugger, etc. It also has a powerful API that allows for batch updating. updeep允许您使用常规(冻结)对象层次结构,因此您可以进行解构,查看日志中的对象和调试器等。它还具有允许批量更新的强大API。 It's not going to be as efficient as Immutable.js for large data sets because it does clone objects if it needs to. 对于大型数据集来说,它不会像Immutable.js那样高效,因为它确实需要克隆对象。

Here's an example (but check those in the README for more): 这是一个例子(但请查看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;
};

The accepted answer should not be the accepted answer. 接受的答案不应该是公认的答案。 You need to initialise state using immutable and then (as mentioned before) use redux-immutablejs 您需要使用immutable初始化状态,然后(如前所述)使用redux-immutablejs

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

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

Than use the combineReducers from redux-immutablejs 比使用redux-immutablejs的combineReducers

Extra tip: Using react-router-redux works pretty well so if you would like to add this then replace the reducer from react-router-redux with this: 额外提示:使用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;
};

Just import this into your root reducer 只需将其导入根减速器即可

This is also stated in the documentation of redux-immutablejs 这在redux-immutablejs的文档中也有说明

Take a look at https://github.com/indexiatech/redux-immutablejs 看看https://github.com/indexiatech/redux-immutablejs

It's pretty much a combineReducer and an optional createReducer that conforms with Redux standards. 它几乎是一个combineReducer和一个符合Redux标准的可选createReducer

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM