5

我有一个包含很多嵌套实体的 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"
    }
  ]
}

使用下面给出的模式对该响应进行标准化normalizr

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

下面是它的外观:

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

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"
      }
  ]
}

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

我保留opening,tagsdocs三个不同的减速器。

这是国家的矛盾。我可以想到以下方法来保持状态一致:

  1. tags我调度一个动作来更新标签并在reducer和reducer中收听它,opening然后在两个地方更新标签。
  2. 使用标签更新开头的补丁请求返回开头响应。我可以再次以适当的一致性调度使响应正常化并设置标签、打开等的操作。

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

4

1 回答 1

5

首先总结一下normalizr工作原理:normalizr将嵌套 API 响应展平到由您的模式定义的实体。因此,当您发出初始GET openingsAPI 请求时,normalizr 将响应展平并创建您的 Reduxentities和展平对象:openingsdocstags

您的建议是可行的,但我发现normalizr将 API 数据与 UI 状态分离的真正好处;所以我不会自己更新 Redux 存储中的数据……我所有的 API 数据都保存在entities其中,我不会更改它们;它们是普通的后端数据......我所做的就是GET在状态更改时执行 API 操作,并规范化GET响应。有一个小的例外DELETE情况,我稍后会详细介绍……中间件会处理这种情况,所以如果你没有使用过,你应该使用一个。我创建了自己的中间件,但我知道redux-promise-middleware非常流行。

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

当您删除一个tag,例如标签[2],在将DELETE请求发送到后端时,您应该在您的实体状态中取消已删除的对象,即。entities.tags[2] = nullGET openings再次更新您的 normalizr 实体之前。

于 2017-06-06T11:26:26.200 回答