在React / Redux reducer中,如何以不可变的方式更新嵌套数组中的字符串?

时间:2017-08-29 02:38:30

标签: javascript arrays reactjs ecmascript-6 redux

我的商店看起来像这样,

{
  name: "john",
  foo: {},
    arr: [
      {
        id:101,
        desc:'comment'
      },
      { 
        id:101,
        desc:'comment2'
      }
    ]
}

我的textarea看起来像这样

<textarea
  id={arr.id} //"101"
  name={`tesc:`}
  value={this.props.store.desc}
  onChange={this.props.onChng}
/>

我的行动是

export const onChng = (desc) => ({
  type: Constants.SET_DESC,
  payload: {
    desc
  }
});

我的减速机

case Constants.SET_DESC:
  return update(state, {
    store: {
      streams: {
        desc: { $set: action.payload.desc }
      } 
    }
});

只有当arry是一个对象时,它才有效,我不得不对数组的流进行更改,我很困惑如何更新到数组,以及如何从商店中获取正确的值。

3 个答案:

答案 0 :(得分:2)

以下来自redux文档的示例可能会帮助您了解如何更新数组中的项目。有关详细信息,请参阅此处http://redux.js.org/docs/recipes/StructuringReducers.html

州结构是这样的

{
  visibilityFilter: 'SHOW_ALL',
  todos: [
    {
      text: 'Consider using Redux',
      completed: true,
    },
    {
      text: 'Keep all state in a single tree',
      completed: false
    }
  ]
}

和reducer代码如下所示

function updateObject(oldObject, newValues) {
    // Encapsulate the idea of passing a new object as the first parameter
    // to Object.assign to ensure we correctly copy data instead of mutating
    return Object.assign({}, oldObject, newValues);
}

function updateItemInArray(array, itemId, updateItemCallback) {
    const updatedItems = array.map(item => {
        if(item.id !== itemId) {
            // Since we only want to update one item, preserve all others as they are now
            return item;
        }

        // Use the provided callback to create an updated item
        const updatedItem = updateItemCallback(item);
        return updatedItem;
    });

    return updatedItems;
}

function appReducer(state = initialState, action) {
    switch(action.type) {
        case 'EDIT_TODO' : {
            const newTodos = updateItemInArray(state.todos, action.id, todo => {
                return updateObject(todo, {text : action.text});
            });

            return updateObject(state, {todos : newTodos});
        } 
        default : return state;
    }
}

答案 1 :(得分:1)

如果必须更新商店中数组中的元素,则必须复制数组并克隆匹配元素以应用更改。

因此,在第一步中,您的操作应包含已克隆(和已更改)的对象或对象的ID以及要更改的属性。

这是一个粗略的例子:

export class MyActions {
    static readonly UPDATE_ITEM = 'My.Action.UPDATE_ITEM';

    static updateItem(id: string, changedValues: any) {
        return { type: MyActions.UPDATE_ITEM, payload: { id, changedValues } };
    }
}

export const myReducer: Reducer<IAppState> = (state: IAppState = initialState, action: AnyAction): IAppState => {
    switch (action.type) {
        case MyActions.UPDATE_ITEM:
            return { ...state, items: merge(state.items, action.payload) };

        default:
            return state;
    }
}

const merge = (array, change) => {
    // check if an item with the id already exists
    const index = array.findIndex(item => item.id === change.id);
    // copy the source array
    array = [...array];

    if(index >= 0) {
        // clone and change the existing item
        const existingItem = array[index];
        array[index] = { ...existingItem, ...change.changedValues };
    } else {
        // add a new item to the array
        array.push = { id: change.id, ...change.changedValues };
    }

    return array;
}

答案 2 :(得分:0)

要更新数组,我会使用immutability helper并执行类似的操作 - 到您的reducer

 let store = {"state" : {
"data": [{
    "subset": [{
        "id": 1
    }, {
        "id": 2
    }]
}, {
    "subset": [{
        "id": 10
    }, {
        "id": 11
    }, {
        "id": 12
    }]
}]
}}

case Constants.SET_DESC:
  return update(store, {
  "state" : {
  "data": {
      [action.indexToUpdate]: {
        "subset": {
             $set: action.payload.desc
        }
      }
  }
 }
  })
  });