【问题标题】:Update existing item or add new item to reducer | React-Redux更新现有项目或将新项目添加到减速器 | React-Redux
【发布时间】:2020-03-04 20:11:13
【问题描述】:

我有一个接收对象数组的要求。我必须检查接收到的对象数组是否已经存在于商店中。如果是,那么我想用旧对象更新新对象,否则我想将新元素添加到商店。

const initialState = {
    ....
    ....
    UserChangedData : {
        ....
        ....
        changedData: []
    }
}

export default function (state = initialState, action) {
    switch(action.type) {
        ....
        ....
        ....
        case SET_USER_BUCKET_LIST_DATA:
            // if there is no userChangedData this condition will run initially
            if (state.UserChangedData.changedData.length === 0) {
                return {
                    ...state,
                    UserChangedData: {
                        ...state.UserChangedData,
                        changedData: [...action.payload]
                    }
                };
            }

            // check if the user item already exists update them. if user item doesn't exists then add 
            // item to UserChangedData's changedData array with existing data. to check if the item 
            // exists or not we can use id.

           // the object which I receive will be an array of object(s)

            // scenario 1 Initial data.
           // [{id:1 , name: "john", gender: "Male"}, {id:2 , name: "peter", gender: "Male"}, {id:3 , 
           //  name: "Natalie", gender: "Female"}, {id:4 , name: "Nicole", gender:"Female"}]

            // scenario 2 : user edited one object with id 1 so update the whole object where the inital 
           // changedData  
           //  example data : [{id:1 , name: "Logan", gender: "Male"}]

           // scenario 3: user edited id: 1  and added a new object with id: 8 so update previous id: 1 
           // with new id: 1 object data and also add new object id: 8 data to changedData array.
           // id: 8 
           // example data: [{id:1 , name: "Jane", gender: "Female"}, {id:8 , name: "Jane", 
           //                 gender:"Female"}

我尝试了很多逻辑,但都没有奏效,谁能建议我上述场景的逻辑。

【问题讨论】:

    标签: reactjs redux react-redux


    【解决方案1】:

    查看 Redux 文档中的 Immutable Update Patterns

    你的场景:

    • 您的状态已正确初始化为空数组,因此您的 state.UserChangedData.changedData 始终是一个数组
    • 在您的case SET_USER_BUCKET_LIST_DATA: 中,您应该创建新变量let newStateChangedData = [...state.UserChangedData.changedData]
    • 循环遍历action.payload 中的所有项目,并为每个项目查看state.UserChangedData.changedData 是否存在
    • 然后始终以这种方式更新您的状态(您的解决方案中的 if 不应该存在):
    return {
        ...state,
        UserChangedData: {
            ...state.UserChangedData,
            changedData: newStateChangedData
        }
    };
    

    【讨论】:

    • 感谢您的建议,我会试试这个并通知您。
    • 我应该如何使用将返回数组的传统 for 循环或映射遍历 action.payload。你能给我看一个代码示例吗?
    • 没有map,一些传统的for循环就可以了。您应该在每个循环中更改 newStateChangedData,例如newStateChangedData = [...newStateChangedData, newAddedItem]
    • 既然我有一个changedData的副本,可以改变数组的副本吗?
    • 不,您应该使用不可变模式来执行此操作,我已将您定向到 redux 文档。这个newStateChangedData = [...newStateChangedData, newAddedItem] 没有变异,这是丢弃旧值并设置新值。
    【解决方案2】:

    据我了解,您希望根据 id 值将 state.UserChangedData.changedData 合并并替换为 action.payload。

    您可以使用以下减速器来实现您想要的:

    const rootReducer = (state = initialState, action) => {
      switch (action.type) {
        case SET_USER_BUCKET_LIST_DATA:
          let updatedChangeData = Object.values(
            []
              .concat(state.UserChangedData.changedData, action.payload)
              .reduce(
                (r, c) => ((r[c.id] = Object.assign(r[c.id] || {}, c)), r),
                {}
              )
          );
    
          return {
            ...state,
            UserChangedData: {
              ...state.UserChangedData,
              changedData: updatedChangeData
            }
          };
    
        default:
          return state;
      }
    };
    

    这个想法来自这篇文章:

    How to merge and replace objects from two arrays based on a key in javascript?

    这是在独立节点应用程序中使用它的完整代码:

    const redux = require("redux");
    const createStore = redux.createStore;
    
    const SET_USER_BUCKET_LIST_DATA = "SET_USER_BUCKET_LIST_DATA";
    
    const initialState = {
      UserChangedData: {
        changedData: []
      }
    };
    
    const rootReducer = (state = initialState, action) => {
      switch (action.type) {
        case SET_USER_BUCKET_LIST_DATA:
          let updatedChangeData = Object.values(
            []
              .concat(state.UserChangedData.changedData, action.payload)
              .reduce(
                (r, c) => ((r[c.id] = Object.assign(r[c.id] || {}, c)), r),
                {}
              )
          );
    
          return {
            ...state,
            UserChangedData: {
              ...state.UserChangedData,
              changedData: updatedChangeData
            }
          };
    
        default:
          return state;
      }
    };
    
    const store = createStore(rootReducer);
    
    store.subscribe(() => {
      console.log("[Subscription]", store.getState().UserChangedData.changedData);
    });
    
    store.dispatch({
      type: SET_USER_BUCKET_LIST_DATA,
      payload: [{ id: 1, title: "A" }]
    });
    
    store.dispatch({
      type: SET_USER_BUCKET_LIST_DATA,
      payload: [{ id: 2, title: "B" }]
    });
    
    store.dispatch({
      type: SET_USER_BUCKET_LIST_DATA,
      payload: [{ id: 1, title: "AA" }]
    });
    

    【讨论】:

    • 非常感谢。这就像一个魅力!您能否向我解释一下 updatedChangeData 部分,这有点令人困惑。
    • @AashayAmbali 它只是根据 id 合并和替换两个数组,我知道这段代码不太容易理解:(但确实有效:)
    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 2020-10-26
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 2019-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多