Как использовать неизменяемый.js с redux?

Redux framework использует редуктор чтобы изменить состояние приложения в ответ на действие.

ключевое требование заключается в том, что редуктор не может изменить существующий объект состояния; он должен создать новый объект.

Плохой Пример:

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

Это хороший вариант использования для незыблемыми.js.

5 ответов


принимая ваш хороший пример с неизменяемым

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

незыблемыми.js должен использоваться в каждом редукторе по мере необходимости, например

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

однако в этом примере много накладных расходов: каждый раз, когда вызывается действие редуктора, он должен преобразовать объект JavaScript в экземпляр неизменяемого, мутировать полученный объект и преобразовать его обратно в объект JavaScript.

лучший подход состоит в том, чтобы иметь начальное состояние экземпляра неизменными:

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 унцию. Тогда каждый редуктор будет рассматривать его как экземпляр Immutable и передать его по линии, как пример Immutable. Загвоздка в том, что теперь вам нужно привести все состояние в JavaScript, прежде чем передавать значения в контекст представления.

если вы выполняете множественные мутации состояния в редукторе, вы можете рассмотреть пакетная обработка мутаций используя .withMutations.

чтобы сделать вещи проще, я разработал redux-неизменяемый библиотека. Он обеспечивает combineReducers функция, эквивалентная функции с тем же именем в пакете redux, за исключением того, что она ожидает, что начальное состояние и все редукторы будут работать с незыблемыми.js


Если вы просто ищете простой способ сделать обновления без мутации, я поддерживаю библиотеку:https://github.com/substantial/updeep что, на мой взгляд, является хорошим способом сделать это с redux.

updeep позволяет работать с обычными (замороженными) иерархиями объектов, поэтому вы можете выполнять деструкцию, видеть объекты в журналах и отладчике и т. д. Она также имеет мощный API, который позволяет пакетного обновления. Она не будет такой же эффективной, как неизменяемой.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;
};

принятый ответ не должен быть принятым ответом. Вам нужно инициализировать состояние с помощью immutable, а затем (как упоминалось ранее) использовать redux-immutablejs

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

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

чем использовать combineReducers из redux-immutablejs

дополнительная подсказка: Использование react-router-redux работает довольно хорошо, поэтому, если вы хотите добавить это, замените редуктор из react-router-redux следующим:

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


посмотри https://github.com/indexiatech/redux-immutablejs

Это combineReducer и дополнительно createReducer Это соответствует стандартам Redux.