2016-04-12 62 views
2

在Redux中使用immutablejs時,我們將從combineReducers中獲得一個常規的javascript對象,這意味着即使其中的所有內容都是不可變的數據結構。這是不是意味着使用immutablejs將是徒勞的,因爲無論如何都會在每個動作上創建一個全新的狀態對象?Redux with Immutable JS

例子:

const firstReducer = (state = Immutable.Map({greeting : 'Hey!'})) => { 
    return state 
} 

const secondReducer = (state = Immutable.Map({foo : 'bar'})) => { 
    return state 
} 

const rootReducer = combineReducers({ 
    firstReducer, secondReducer 
}) 

回答

5

一個全新的狀態對象將在每一個動作

是的,但是由combineReducers分配不會被重建該國的片創建。這有點類似於這樣:

const person = { name: 'Rob' }; 
const prevState = { person }; 
const nextState = { person }; 

我創建了一個新的狀態對象(nextState),但其person關鍵仍設置爲完全相同的對象是prevStateperson關鍵。內存中只有一個字符串'Rob'的實例。

問題是,當我的變異對象person,我改變了它的多種狀態:

const person = { name: 'Rob' }; 
const prevState = { person }; 
person.name = 'Dan'; // mutation 
const nextState = { person }; 

console.log(prevState.person.name); // 'Dan' 

反觀Redux的,一旦所有減速都被稱爲是第一次,他們將初始化他們的應用程序的狀態,以及應用程序的整個整體狀態的片將基本上等於這樣的:

{ 
    firstReducer: Immutable.Map({greeting : 'Hey!'}), 
    secondReducer: Immutable.Map({foo : 'bar'}), 
} 

注意,這是一個正常的對象。它具有保存不可變對象的屬性。

當一個動作被調度並且通過每個reducer時,就會得到它,reducer只是簡單地返回現有的Immutable對象,它不會創建一個新的。然後,將新狀態設置爲一個對象,該對象的屬性firstReducer只是簡單地指向與之前狀態指向的相同的不可變對象。現在

,如果我們沒有爲firstReducer用什麼永恆:

const firstReducer = (state = {greeting : 'Hey!'}) => { 
    return state 
} 

同樣的想法,那就是用作默認爲在減速機首次調用只是從以前的狀態傳遞狀態對象到下一個狀態。內存中只有一個對象具有密鑰greeting和值Hey!。有許多狀態對象,但它們只有一個指向相同對象的密鑰firstReducer

這就是爲什麼我們需要確保我們不會意外地改變它,而是在我們改變它的任何事情時將其替換掉。你可以通過小心來完成這項工作,而不用固定,但使用Immutable使它更加簡單。沒有一成不變的,它可能搞砸了,並做到這一點:

const firstReducer = (state = {greeting : 'Hey!'}, action) => { 
    switch (action.type) { 
    case 'CAPITALIZE_GREETING': { 
     const capitalized = state.greeting.toUpperCase(); 
     state.greeting = capitalized; // BAD!!! 
     return state; 
    } 
    default: { 
     return state; 
    } 
    } 
} 

的正確方法是創建一個新的狀態切片:

const firstReducer = (state = {greeting : 'Hey!'}, action) => { 
    switch (action.type) { 
    case 'CAPITALIZE_GREETING': { 
     const capitalized = state.greeting.toUpperCase(); 
     const nextState = Object.assign({}, state, { 
     greeting: capitalized, 
     }; 
     return nextState; 
    } 
    default: { 
     return state; 
    } 
    } 
} 

另一個好處永恆帶給我們的是,如果我們的減速機的片除了greeting之外,Immutable可能會進行一些優化,因此如果我們所做的只是更改單個值,但它仍然不需要重新創建每一條數據確保不變的同時。這非常有用,因爲它可以幫助減少每次分派操作時內存中內存的數量。

2

combineReducers()隨終極版確實給你一個簡單的根對象。

這不是問題本身,你可以用不可變對象,只要搭配簡單的對象,你不變異他們。所以你可以忍受這一切就好了。

您也可以使用alternative combineReducers()返回一個不可變的映射來代替。這完全取決於你,除了它可以讓你在任何地方使用Immutable之外,沒有什麼大的區別。

不要忘記,combineReducers()實際上是easy to implement on your own

這是否意味着使用immutablejs將是徒勞的,因爲無論如何都會在每個動作上創建一個全新的狀態對象?

我不確定你的意思是「徒勞」。 Immutable不會奇蹟般地阻止創建對象。當你在set()的Immutable Map中,你仍然創建一個新的對象,只是(在某些情況下)更有效率。無論如何,當你有兩個鍵的情況下,這並沒有什麼不同。

所以不是使用Immutable這裏並沒有真正的缺點,除了你的應用在數據結構的選擇上稍微不一致。

+0

謝謝你的回答。我主要是指內存使用和新對象的創建。羅布在他的回答中釘了它。 – swelet

+0

啊,我明白了。常見問題也涉及這個主題:http://redux.js.org/docs/FAQ.html#performance-clone-state –