【问题标题】:How do I handle nested API responses in a Flux application?如何处理 Flux 应用程序中的嵌套 API 响应?
【发布时间】:2025-12-01 10:35:01
【问题描述】:

我正在将现有应用程序移植到 Flux,但我对一个主题有点困惑。 假设我有几个返回两级或三级嵌套对象的 API 端点。

例如,GET /articles 可能会返回 schema 的 JSON 响应

articles: article*

article: {
  author: user,
  likers: user*
  primary_collection: collection?
  collections: collection*
}

collection: {
  curator: user
}

如你所见,不同层次的用户有各种各样的嵌套:

  • articles[i].author
  • articles[i].likers[i]
  • articles[i].primaryCollection.curator
  • articles[i].collections[i].curator

如果我想在任何时候获取文章时用新数据更新UserStore,我必须编写一个可怕的方法来检查文章 API 响应中的所有嵌套实体。此外,还会有很多重复,因为还有其他 API 端点具有不同的架构,有时文章会嵌入到用户内部(例如GET /user/published)。

Flux 商店是否有一种更简洁的方法来从所有 API 响应中提取嵌套实体?

【问题讨论】:

    标签: json architecture nested cqrs flux


    【解决方案1】:

    Jing Chen(Flux 的创建者和传播者之一)建议的一种方法是在 API 响应到达 Store 之前将其展平。我写了一个小型库来做到这一点:它规范化

    [{
      id: 1,
      title: 'Some Article',
      author: {
        id: 1,
        name: 'Dan'
      }
    }, {
      id: 2,
      title: 'Other Article',
      author: {
        id: 1,
        name: 'Dan'
      }
    }]
    

    {
      result: [1, 2],
      entities: {
        articles: {
          1: {
            id: 1,
            title: 'Some Article',
            author: 1
          },
          2: {
            id: 2,
            title: 'Other Article',
            author: 1
          }
        },
        users: {
          1: {
            id: 1,
            name: 'Dan'
          }
        }
      }
    }
    

    (注意没有重复,结构是扁平的。)

    Normalizr 让您:

    • 在其他实体、对象和数组中嵌套实体
    • 结合实体模式来表达任何类型的 API 响应
    • 自动合并具有相同 ID 的实体(如果它们不同,则会发出警告)
    • 使用自定义 ID 属性(例如 slug)

    要使用它,您需要定义实体和嵌套规则并使用它们来转换 JSON:

    var normalizr = require('normalizr'),
        normalize = normalizr.normalize,
        Schema = normalizr.Schema,
        arrayOf = normalizr.arrayOf;
    
    // First, define a schema:
    
    var article = new Schema('articles'),
        user = new Schema('users'),
        collection = new Schema('collections');
    
    // Define nesting rules:
    
    article.define({
      author: user,
      collections: arrayOf(collection)
    });
    
    collection.define({
      curator: user
    });
    
    
    // Usage:
    
    // Normalize articles
    var articlesJSON = getArticleArray(),
        normalized = normalize(articlesJSON, arrayOf(article));
    
    // Normalize users
    var usersJSON = getUsersArray(),
        normalized = normalize(usersJSON, arrayOf(user));
    
    // Normalize single article
    var articleJSON = getArticle(),
        normalized = normalize(articleJSON, article);
    

    这允许您在将任何 XHR 响应传递给 Flux Dispatcher 之前对其进行规范化。 商店只需要从相应的字典中更新自己:

    // UserStore
    
    UserStore.dispatchToken = AppDispatcher.register(function (payload) {
      var action = payload.action;
    
      switch (action.type) {
      // you can add any normalized API here since that contains users:
      case ActionTypes.RECEIVE_ARTICLES:
      case ActionTypes.RECEIVE_USERS:
    
        // Users will always be gathered in action.entities.users
        mergeInto(_users, action.entities.users);
        UserStore.emitChange();
        break;
      }
    });
    
    
    // ArticleStore
    
    AppDispatcher.register(function (payload) {
      var action = payload.action;
    
      switch (action.type) {
      // you can add any normalized API here since that contains articles:
      case ActionTypes.RECEIVE_ARTICLES:
    
        // Wait for UserStore to digest users
        AppDispatcher.waitFor([UserStore.dispatchToken]);
    
        // Articles will always be gathered in action.entities.articles
        mergeInto(_articles, action.entities.articles);
        ArticleStore.emitChange();
        break;
      }
    });
    

    【讨论】:

    • 规范化如何处理需要传回服务器以进行 UPDATE/POST 的数据?
    • 你也可以使用 normalizr 去规范化。
    最近更新 更多