2016-12-07 42 views
8

我有一個待辦事項列表,並希望將該項目的狀態設置爲「完成」,如果用戶點擊「完成」。更新項目數組| |中的單個值反應減少

這裏是我的行動:

export function completeTodo(id) { 
    return { 
     type: "COMPLETE_TASK", 
     completed: true, 
     id 
    } 
} 

這裏是我的減速器:

case "COMPLETE_TASK": { 
      return {...state, 
       todos: [{ 
        completed: action.completed 
       }] 
      } 
     } 

我有是新的狀態也不再有文本的待辦事項上相關的問題選定的項目和ID不再存在。這是因爲我覆蓋了狀態並忽略了以前的屬性?我的物品onload看起來像這樣:

Objecttodos: Array[1] 
    0: Object 
     completed: false 
     id: 0 
     text: "Initial todo" 
    __proto__: Object 
    length: 1 
    __proto__: Array[0] 
    __proto__: Object 

正如你所看到的,我想要做的就是將完成的值設置爲true。

回答

29

您需要轉換您的todos數組才能更新相應的項目。 Array.map是最簡單的方法:

case "COMPLETE_TASK": 
    return { 
     ...state, 
     todos: state.todos.map(todo => todo.id === action.id ? 
      // transform the one with a matching id 
      { ...todo, completed: action.completed } : 
      // otherwise return original todo 
      todo 
     ) 
    }; 

有一些庫可以幫助您進行這種深度狀態更新。你可以找到這樣的庫的列表,在這裏:https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md#immutable-update-utilities

就個人而言,我用這與其updateInsetIn方法(這比正常的對象和數組的有很多按鍵的大型物體更有效的解決了這個問題ImmutableJS(https://facebook.github.io/immutable-js/)和數組,但小的慢)。

+0

感謝您的幫助TomW並感謝您的引用關於深州更新庫。很好的幫助! – Filth

+0

我看到你正在使用單行if語句,雖然我發現它很難閱讀。如果有陳述,我知道減速器炸彈。你能解釋這裏發生了什麼,也可能是另一種寫這種邏輯的方式嗎? – Filth

+0

當你不從每個分支返回狀態時,減速器的'炸彈' - '如果'語句沒問題,只是你需要確保你'返回狀態';'在'if'之後。如果你看看這裏的TOGGLE_TODO處理程序:http://redux.js.org/docs/basics/Reducers.html#handling-more-actions你會看到一個非常類似於我的例子,它使用了'if'語句而不是'?:' - '?:'與if語句相比稍有好處,因爲它強制您從每個分支返回一個值。 – TomW

1

新狀態並不再有待辦事項項目上 所選擇的項目相關聯的文本和ID不再存在,這是因爲我 覆蓋狀態,而忽略以前的屬性?

是的,因爲每次更新時要分配與只有一個completed一個新的數組,數組不包含任何以前的值。所以更新數組之後沒有以前的數據。這就是爲什麼文本和身份證更新後不在那裏。

解決方案:

使用array.map找到那麼正確的元素來更新值,就像這樣:

case "COMPLETE_TASK": 
    return { 
     ...state, 
     todos: state.todos.map(todo => 
      todo.id === action.id ? { ...todo, completed: action.completed } : todo 
     ) 
    }; 

2 - 使用array.findIndex地發現,特定對象的索引然後更新一下,像這樣:

case "COMPLETE_TASK": 
    let index = state.todos.findIndex(todo => todo.id === action.id); 
    let todos = [...todos]; 
    todos[index] = {...todos, completed: action.completed}; 
    return {...state, todos} 

檢查這個片段中,你會得到關於你正在做的錯誤一個更好的主意:

let state = { 
 
    a: 1, 
 
    arr: [ 
 
    {text:1, id:1, completed: true}, 
 
    {text:2, id:2, completed: false} 
 
    ] 
 
} 
 

 
console.log('old values', JSON.stringify(state)); 
 

 
// updating the values 
 

 
let newState = { 
 
    ...state, 
 
    arr: [{completed: true}] 
 
} 
 

 
console.log('new state = ', newState);

0

一個具有開創性的設計原則REACT爲「不要變異狀態。「如果你想改變數組中的數據,你想創建一個新的數組,其中包含已更改的值。

例如,我有一個狀態結果數組。 0在我的構造函數中的每個索引。

this.state = {   
     index:0, 
     question: this.props.test[0].questions[0], 
     results:[[0,0],[1,0],[2,0],[3,0],[4,0],[5,0]], 
     complete: false   
}; 

後來,我想更新數組中的值。但我不在狀態對象改變它。隨着ES6,我們可以利用的傳播運營商。數組切片方法返回一個新的數組,它不會改變現有的數組。

updateArray = (list, index,score) => { 
    // updates the results array without mutating it 
     return [ 
     ...list.slice(0, index), 
     list[index][1] = score, 
     ...list.slice(index + 1) 
    ]; 
}; 

當我wan噸至更新數組中的一個項目,我打電話updateArray和一氣呵成設置狀態:

this.setState({ 
     index:newIndex, 
     question:this.props.test[0].questions[newIndex], 
     results:this.updateArray(this.state.results, index, score) 
});