2017-01-01 38 views
3

方面變化值深Redux的狀態

我渲染形式一組動態文本元素。我已經使用normalizr principles規範了我的狀態,所以有一個elementIds數組和一個包含elementIds引用的元素屬性的對象(請參閱下面代碼示例中的初始狀態)。

目的

我的目的是簡單地對兩個渲染的元素是可編輯的。我使用onChange回調函數成功地將一個動作CHANGE_ELEMENT_VALUE分配給我的商店,在reducer中可以使用action.id(引用已更改元素的id)和action.value(新值)(請參閱下面的代碼)。

問題

我的問題是,當我鍵入文本字段沒有發生變化,即使我可以看到使用devtools Redux的擴展狀態改變。我的理解是,反應並不能識別狀態變化,因爲變化是深入的狀態,而且我沒有成功創建一個新的狀態對象,我可能以某種方式引用舊的實例。

減速碼

下面是我的拙劣企圖迫使一個新的狀態對象。我假設它不工作,因爲我的組件沒有被重新渲染。它也顯得非常不雅。

let initialState = { 
    isLoading: false, 
    data: { 
     elementIds: ['name', 'email'], 
     elements: { 
      'name': {'id': 'name', 'value':'ben'}, 
      'email': {'id':'email', 'value':'[email protected]'}, 
     }, 
    }, 
    error: false 
} 

function formReducer(state = initialState, action = null) { 
    switch(action.type) { 
     case types.CHANGE_ELEMENT_VALUE: 
      let newData = Object.assign(state.data) 
      newData.elements[action.id].value = action.value 
      return {...state, data: newData} 

     default: 
      return state; 
    } 
} 

export default formReducer; 
+0

我注意到的第一個問題是您濫用Object.assign。如果你測試它,你可以看到'newData === state.data',這是因爲第一個參數是目標。一般來說,你總是會有這個深層次克隆對象的「問題」(如果結構是動態的,它會變得更醜),所以下面的答案可能對你有用。我個人使用https://www.npmjs.com/package/icepick –

回答

2

,您可以利用的immutability-helper npm package並在減速機更新你的價值觀

import update from 'immutability-helper'; 

let initialState = { 
    isLoading: false, 
    data: { 
     elementIds: ['name', 'email'], 
     elements: { 
      'name': {'id': 'name', 'value':'ben'}, 
      'email': {'id':'email', 'value':'[email protected]'}, 
     }, 
    }, 
    error: false 
} 

function formReducer(state = initialState, action = null) { 
    switch(action.type) { 
     case types.CHANGE_ELEMENT_VALUE: 
      return update(state, { 
       data : { 
        elements: { 
         [action.id]: { 
           value: { 
            $set: 'new value' 
           } 
          } 
        } 
       } 
      }) 

     default: 
      return state; 
    } 
} 

export default formReducer; 

update()提供簡單句法糖圍繞此模式使 更容易編寫此代碼。儘管語法花了一些時間去使用 (儘管它受MongoDB查詢語言的啓發),但沒有多餘的餘地,它是靜態分析的,並且它不比更改版本更容易輸入 。

+0

謝謝@ shubham-khatri。你或其他人是否有意見認爲這是否比上面提到的深度延伸選項更好? – xanld

1

Object.assign只能操作一級深度;即它不遞歸地克隆整個對象樹。因此,您的頂級對象被克隆,但它不會觸發重新渲染,因爲您的Reducer會在克隆的對象中突變一個值。

我會建議尋找到deep-extend包和更新您的狀態如下:

import extend from 'deep-extend'; 

... 

return extend(state, { 
    elements: { 
    [key]: value 
    } 
}); 
+0

這看起來很方便。我是否應該對任何表現處罰或對我的狀態結構的擔憂以及我不得不在整個關鍵筆畫上覆制樹的整個部分這一事實感到擔心,只需將一個值改爲一個字符? – xanld