Redux - 从嵌套在另一个数组中的数组中删除对象

时间:2017-08-29 10:38:33

标签: javascript arrays ecmascript-6 redux

我的Redux状态存储一个comments对象,该对象存储一系列注释。每个comment对象中都有一个replies数组。我将父评论ID和回复ID都传递给我的reducer,目的是从回复数组中删除回复。

我的顶级评论对象的简化版本如下所示:

{
  "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: "",
}

这是我的reducer,它似乎将父注释对象包装在一个数组中并展平回复(显然不是所需的结果,但我对解决嵌套数组的最佳方法感到茫然)。

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;
}

2 个答案:

答案 0 :(得分:3)

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

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

尽管normalizer是一个非常标准化的状态标准工具,但我建议您首先编写自己的标准。通过这种方式我学到了很多东西。

什么是规范化数据结构?

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

Dan Abramov(建立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()通过我们的allIds数组,并使用第一个参数来访问密钥以获取数据。

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

以同样的方式,并回答您的问题,您可以使用filter()代替map()删除元素。我不打算在这里解释过滤器。需要十秒钟才能找到比我能解释的更好的例子。

然后确保您遵循标准的Redux方式。

  1. 使用reducer复制数据结构。你的州应该在没有数据的情况下初始化......这样你就知道你做得对了。

  2. 编写处理它的特定状态的减速器(注释减速器等)对我来说,这些通常由返回状态或返回新状态的switch语句组成。

  3. 编写为减速器提供所需新数据的操作。 始终遵循使用函数处理一项工作的JS原则。操作不应该做多件事。

  4. 注意但是使用像thunk这样的中间件,操作可以调度其他可能导致逻辑非常棒的操作!

    评论的删除操作可能看起来像

    那样简单
    function deleteComment(commentId) {
      return {
        type: "delete project",
        payload: commentId
      }
    }
    

    这给了我们所需要的一切。 通过在我们的reducer中使用前面提到的switch语句,我们可以检查查看正在调度的type操作。 (这告诉我们如何处理提供的数据)以及要删除的元素,即有效负载。

    您可以按照这种简单的方法来满足85%的应用需求。

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

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

答案 1 :(得分:2)

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

但是,如果您需要更新现有结构,请执行以下步骤:

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

    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());