2017-08-29 123 views
0

My Redux状态存储一个存储注释数组的对象comments。每个comment对象都有一个replies数组。我将父注释ID和回复ID都传递给我的reducer,意图从回复数组中删除回复。Redux - 从嵌套在另一个阵列中的阵列中删除对象

我的顶级评论对象的简化版本是这样的:

{ 
    "count": 4, 
    "data": [ 
    { 
     id: 123, 
     text: 'This is a comment', 
     replies: [ 
     { 
      id: 479, 
      text: 'This is a reply', 
     }, 
     { 
      id: 293, 
      text: 'This is another reply', 
     }, 
     ], 
    }, 
    { 
     id: 728, 
     text: 'This is another comment', 
     replies: [ 
     { 
      id: 986, 
      text: 'This is a reply', 
     }, 
     ], 
    }, 
    ], 
    "pageSize": 5, 
    cursor: "", 
} 

这里是我的减速器出现包裹父评论对象的数组和扁平的答复(显然不是期望结果,但我对处理嵌套数组的最佳方式感到不知所措)。

case types.DELETE_REPLY_SUCCESS: { 
    const content = Object.assign({}, state); 
    content.data = content.data.map((comment) => { 
    const newObj = { ...comment }; 
    if (newObj.id === action.parentCommentId) { 
     return newObj.replies.filter(reply => reply.id !== action.replyId); 
    } 
    return newObj; 
    }); 
    return content; 
} 

回答

1

更新嵌套结构在redux中可能非常令人讨厌。我建议使用平坦的结构。您可以使用normalizer或手动执行此操作。

然而,如果你需要更新你的现有结构,这些步骤如下:

  1. 找到您想要更改注释的索引。
  2. 为评论创建一个新的过滤回复数组。
  3. 通过用包含新答复阵列的新评论替换旧评论来创建新数据阵列。
  4. 用新的数据数组创建一个新的状态对象。

const state = {"count":4,"data":[{"id":123,"text":"This is a comment","replies":[{"id":479,"text":"This is a reply"},{"id":293,"text":"This is another reply"}]},{"id":728,"text":"This is another comment","replies":[{"id":986,"text":"This is a reply"}]}],"pageSize":5,"cursor":""}; 
 

 
const action = { 
 
    parentCommentId: 123, 
 
    replyId: 479 
 
}; 
 

 
const deleteReplySuccess =() => { 
 
    const data = state.data; 
 
    
 
    // find the index of the comment you want to update 
 
    const commentToChangeIndex = data.findIndex(({ id }) => id === action.parentCommentId); 
 
    
 
    // if it doesn't exist return the state 
 
    if(commentToChangeIndex === -1) { 
 
    return state; 
 
    } 
 
    
 
    // get the comment 
 
    const comment = data[commentToChangeIndex]; 
 
    
 
    // create an updated comment with filtered replies array 
 
    const updatedComment = { 
 
    ... comment, 
 
    replies: comment.replies.filter(reply => reply.id !== action.replyId) 
 
    }; 
 

 
    // create a new state using object spread or assign 
 
    return { 
 
    ...state, 
 
    data: [ // create a new data array 
 
     ...data.slice(0, commentToChangeIndex), // the comments before the updated comment 
 
     updatedComment, // the updated comment 
 
     ...data.slice(commentToChangeIndex + 1) // the comments after the updated comment 
 
    ] 
 
    }; 
 
}; 
 

 
console.log(deleteReplySuccess());

1

上面的答案是更直接的,但我想分享我的一些想法。

首先,this Redux中正常化状态下的链接解决了我的一个大问题......处理嵌套数据结构......您的代码变得非常复杂。 90%的减速器应该非常简单。 随着嵌套数据结构,它们变得复杂

尽管标准化程序是一个非常标准化的状态标准化工具,我建议您首先编写自己的标准化程序。我从这样做中学到了很多东西。

什么是归一化数据结构?

它是平坦的。它通常是关系型的。

丹·阿布拉莫夫(谁建立了Redux),建议存储分组数据。所以你的意见成为一个团体,你的回复共享另一个。就像在关系数据库中一样。每个“组”都有自己的“桌子”。

起初,这似乎与我不直观,因为它感觉你正在编写更多的数据结构。你不是......而且收益非常值得。

所以,你会存储你的数据是这样的

{ 
    "comments": { 
    "allIds" : [1,2,3,4], 
    "byId": { 
     1: { 
     replies: [12], 
     comment: "a comment" 
     }, 
     2: { 
     replies: [13], 
     comment: "another comment" 
     }, 
     3: { 
     replies: [14], 
     comment: "one more comment" 
     }, 
     4: { 
     replies: [15], 
     comment: "oh look, a comment" 
     }, 
    } 
    }, 
    "replies" : { 
    "allIds" : [12,13,14,15], 
    "byId": { 
     12: { 
     comments: [1], 
     reply: "a reply" 
     }, 
     13: { 
     comments: [2], 
     reply: "another reply" 
     }, 
     14: { 
     comments: [3], 
     reply: "yet another reply" 
     }, 
     15: { 
     comments: [4], 
     reply: "a reply" 
     } 
    } 
} 

为什么大不了的?

这是什么方式让生活更轻松?首先,如果我们想要显示评论列表,我们可以通过我们的​​阵列map()并使用第一个参数访问密钥以获取数据。

这意味着我们可以遍历单个数组而不是通过嵌套对象。

以同样的方式,并在回答你的问题您可以通过使用filter()代替map()删除元素。我不会在这里解释过滤器,它需要十秒才能找到比我能解释的任何东西都好的例子。

然后只要确保你遵循了标准的Redux做事的方式。

  1. 使用reducer复制您的数据结构。你的状态应该没有数据初始化......这样你就知道你做对了。

  2. 编写你的reducer来处理它的特定状态(comments reducer等)对于我来说,这些通常由switch语句组成,它们返回状态或返回一个新状态。

  3. 编写为减速器提供所需新数据的操作。 始终遵循JS的一个功能来处理一项工作的原则。行动不应该做很多事情。

注意但是使用中间件喜欢的thunk,动作可调度这可能会导致逻辑迷死其他行动!

的评论删除操作可能看起来那样简单

function deleteComment(commentId) { 
    return { 
    type: "delete project", 
    payload: commentId 
    } 
} 

这给我们所有我们需要的。 通过使用我们的reducer中前面提到的switch语句,我们可以检查看到哪些type行动正在分派。 (这告诉我们如何处理提供的数据)以及要删除的元素,即有效载荷。

您可以按照这种简单的方法处理85%的应用程序需求。

我知道还有很多Redux比这个更多,但这种方法确实帮助我了解如何查看Redux以及如何管理和操纵状态。 我强烈推荐通过上面链接的Dan Abramov的整个eggheads.io教程。他在解释几乎所有细节方面做得非常出色。

我希望你的简短问题的这个长答案有所帮助。