Redux + Normalizr:在Redux状态下添加和删除规范化实体

Gau*_*mar 3 redux normalizr react-redux redux-actions

我有一个包含很多嵌套实体的API响应。我使用normalizr来保持redux状态尽可能平坦。
例如。api响应如下所示:

{
  "id": 1,
  "docs": [
    {
      "id": 1,
      "name": "IMG_0289.JPG"
    },
    {
      "id": 2,
      "name": "IMG_0223.JPG"
    }
  ],
  "tags": [
    {
      "id": "1",
      "name": "tag1"
    },
    {
      "id": "2",
      "name": "tag2"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

normalizr使用以下给出的模式对该响应进行规范化:

const OpeningSchema = new schema.Entity('openings', {
    tags: [new schema.Entity('tags')],
    docs: [new schema.Entity('docs')]
});
Run Code Online (Sandbox Code Playgroud)

下面是它的外观:

{
  result: "1",
  entities: {
    "openings": {
       "1": {
          "id": 1,
          "docs": [1,2],
          "tags": [1,2]
       }
    },
    "docs": { 
      "1": { 
        id: "1",
        "name": "IMG_0289.JPG"
      },
      "2": { 
        id: "2",
        "name": "IMG_0223.JPG"
      }
    },
    "tags": {
      "1": {
          "id": 1,
          "name": "tag1"
      },
      "2": {
          "id": 2,
          "name": "tag2"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,redux状态如下所示:

state = {
  "opening" : {
      id: 1,
      tags: [1,2],
      docs: [1,2]
  },
  "tags": [
      {
          "id":1,
          "name": "tag1"
      },
      {
          "id":2,
          "name": "tag2"
      }
  ],
  "docs": [
      {
          "id":1,
          "name": "IMG_0289.JPG"
      },
      {
          "id":2,
          "name": "IMG_0223.JPG"
      }
  ]
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我分派一个动作来添加tag,那么它会添加一个tag对象,state.tags但不会更新state.opening.tags数组。删除标签时也具有相同的行为。

我保留openingtagsdocs使用三种不同的减速器。

这是一个不一致的状态。我可以想到以下几种保持状态一致的方法:

  1. 我调度了一个动作来更新标签,并在tagsreducer和openingreducer中监听它,并随后在两个地方更新标签。
  2. 使用标签更新打开的补丁请求将返回打开响应。我可以再次调度标准化响应的操作,并以适当的一致性设置标签,打开等。

什么是正确的方法来做到这一点。实体不应该观察相关实体的更改并自行进行更改。或者,任何其他模式都可以遵循任何此类操作。

小智 5

首先总结一下normalizr工作原理:将normalizr嵌套API响应展平到您的模式定义的实体。所以,当你做了最初的GET openingsAPI请求,normalizr扁平响应,并创建了终极版entities和扁平对象:openingsdocstags

您的建议是可行的,但我发现normalizr将API数据与UI状态分开确实有好处。因此,我自己不会更新Redux存储中的数据。我的所有API数据均保存在其中,entities并且它们不会被我更改;它们是原始的后端数据...我要做的就是GET根据状态更改API操作并标准化GET响应。对于DELETE案例,有一个小例外,我将在以后进行扩展...中间件将处理此类案例,因此如果您没有使用过,则应使用其中一种。我创建了自己的中间件,但是我知道redux-promise-middleware很受欢迎。

在上面的数据集中;当您添加一个新的时tag,我假设您正在创建一个API POST来这样做,这反过来又更新了后端。然后,您应该执行另一个操作GET openings,该操作将更新entitiesfor开口及其所有嵌套模式。

当您删除tag,例如tag [2]时,在将DELETE请求发送至后端时,应在实体状态(即)中使已删除的对象无效。entities.tags[2] = nullGET openings再次更新您的normalizr实体之前。