2015-08-08 5 views
48

Redux framework использует reducers, чтобы изменить состояние приложения в ответ на действие.Как использовать Immutable.js с сокращением?

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

Дурной пример:

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.

+1

Вы можете увидеть, как это делается здесь https://github.com/este/este – Restuta

+3

правила @Restuta Stack Overflow требуют, чтобы вы раскрыть ваши отношения с третьим -партийный продукт, который вы рекомендуете/ссылаетесь/рекламируете, http://meta.stackexchange.com/questions/94022/how-can-i-link-to-an-external-resource-in-a-community-friendly- В этом случае вы являетесь одним из участников. – Gajus

+34

Я не думаю, что проект OSS-шаблона подходит для «стороннего продукта», и мой комментарий квалифицируется как «ответ». Это просто комментарий, если вы внимательно посмотрите, мой вклад в этот проект был одной из строк, которая позже была отменена. Прошу прощения, но я не могу держать такие незначительные вещи в виду, когда я обращаюсь к чему-то (так как o много способствуют). Я признаю, что я являюсь автором. Не знаете, в чем смысл вашего комментария, вы чувствуете, что я его рекламирую? Примите мое слово - я не, я просто видел там, где работает, идиоматично. – Restuta

ответ

45

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

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

Можете ли вы рассказать о том, почему вы считаете, что этот подход не будет работать с combReducers? Я протестировал это, и насколько я могу судить (также, прочитав код для combReducers, который вы связали) - не должно быть ничего, что мешает этому работать. –

+0

Кажется, это работает для меня с 'combReducers'. @GajusKuizinas, можете ли вы объяснить, почему это не сработает? – Junaid

+6

Он работает в redux @ 3 +. Отлично! – Gajus

23

Иммутируемый.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 перед передачей значений в контекст представления.

Если вы выполняете несколько мутаций состояния в редукторе, вы можете рассмотреть batching mutations с помощью .withMutations.

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

+3

Не должно ли государство содержать ссылку на неизменяемый объект? Использование Immutable для преобразования объекта в Immuttable, а затем обратно к объекту, кажется, теряет некоторые преимущества Immutable. Например, возможность внесения будущих изменений в объект Immutable, в котором библиотека Immutable.js будет эффективно делать эти изменения для вас. Мысли? – richardaday

+0

@richardaday Я предполагаю, что вы имеете в виду реализацию 'redux-immutable'. Если да, то лучше всего открыть вопрос в рамках репо. – Gajus

+0

Должно ли это быть new_state = state.set ('activeLocationId', action.id), а затем возвращать new_state? – danmaz74

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

Какое преимущество имеет преимущество при использовании Immutable.js? – Gajus

+0

tl; dr: pro: отладка, разрушение, улучшение api (imo) См. Раздел мотивации: https://github.com/substantial/updeep#motivation –

+0

[Он появляется] (https://github.com/substantial/ updeep/graphs/contributors), вы присоединяетесь к updeep. Обратите внимание, что наша [политика саморекламы] (http://meta.stackexchange.com/questions/57497) требует раскрытия этой информации в ответах, подобных этой. – josliber

5

Принятый ответ не должен быть принятым ответом. Вы должны инициализировать состояние с помощью неизменны и чем, как упоминалось ранее использование 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

Дополнительный совет: Использование реагировать-маршрутизатор-перевождь работает довольно хорошо, так если вы хотели бы добавить это то заменить редуктор от среагировать-маршрутизатора-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

+1

Обратите внимание, что 'redux-immutable' теперь официально предпочитается' redux-immutablejs'. См. https://github.com/gajus/redux-immutable/issues/12#issuecomment-176189454 и http://redux.js.org/docs/introduction/Ecosystem.html#utilities – Gajus

+0

Почему вы должны использовать redux-immutable? – dardub

+0

Redux уже поддерживает неизменяемый, нет необходимости использовать сокращаемый-неизменный – gusgard

Смежные вопросы