应该在 Flux 应用程序中的哪个位置发出 ajax 请求?

2022-08-30 01:25:22

我正在创建一个具有 flux 架构的 react.js应用程序,并且我正在尝试确定应该在何时何地从服务器请求数据。有没有一个例子可以做到这一点。(不是待办事项应用程序!


答案 1

我非常支持将异步写入操作放在操作创建器中,将异步读取操作放在存储中。目标是将存储状态修改代码保留在完全同步的操作处理程序中;这使得它们易于推理,单元测试也很简单。为了防止对同一端点的多个同时请求(例如,双重读取),我将实际请求处理移动到一个单独的模块中,该模块使用 promise 来防止多个请求;例如:

class MyResourceDAO {
  get(id) {
    if (!this.promises[id]) {
      this.promises[id] = new Promise((resolve, reject) => {
        // ajax handling here...
      });
    } 
    return this.promises[id];
  }
}

虽然存储中的读取涉及异步函数,但有一个重要的警告,即存储不会在异步处理程序中更新自身,而是触发操作,并且仅在响应到达时才触发操作。此操作的处理程序最终执行实际状态修改。

例如,组件可以执行以下操作:

getInitialState() {
  return { data: myStore.getSomeData(this.props.id) };
}

商店将实现一个方法,也许,如下所示:

class Store {
  getSomeData(id) {
    if (!this.cache[id]) {
      MyResurceDAO.get(id).then(this.updateFromServer);
      this.cache[id] = LOADING_TOKEN;
      // LOADING_TOKEN is a unique value of some kind
      // that the component can use to know that the
      // value is not yet available.
    }

    return this.cache[id];
  }

  updateFromServer(response) {
    fluxDispatcher.dispatch({
      type: "DATA_FROM_SERVER",
      payload: {id: response.id, data: response}
    });
  }

  // this handles the "DATA_FROM_SERVER" action
  handleDataFromServer(action) {
    this.cache[action.payload.id] = action.payload.data;
    this.emit("change"); // or whatever you do to re-render your app
  }
}

答案 2

Fluxxor有一个与API进行异步通信的示例。

这篇博客文章已经谈到了它,并已在 React 的博客上进行了专题介绍。


我发现这是一个非常重要且困难的问题,尚未得到明确的答案,因为前端软件与后端的同步仍然是一个痛苦的问题。

API 请求是否应该在 JSX 组件中发出?商店?其他地方?

在商店中执行请求意味着,如果 2 个商店需要相同的数据来执行给定的操作,它们将发出 2 个类似的请求(除非您在商店之间引入依赖关系,我真的不喜欢)

就我而言,我发现将Q承诺作为操作的有效载荷非常方便,因为:

  • 我的操作不需要可序列化(我不保留事件日志,我不需要事件溯源的事件重播功能)
  • 它消除了具有不同操作/事件(请求激发/请求完成/请求失败)的需要,并且在可以触发并发请求时必须使用相关 ID 进行匹配。
  • 它允许多个存储来侦听同一请求的完成,而不会在存储之间引入任何依赖关系(但是引入缓存层可能更好?

阿贾克斯是邪恶的

我认为Ajax在不久的将来会越来越少被使用,因为它很难解释。正确的方法?将设备视为分布式系统的一部分,我不知道我第一次遇到这个想法的地方(也许在这个鼓舞人心的克里斯格兰杰视频中)。

想想吧。现在,对于可扩展性,我们使用具有最终一致性的分布式系统作为存储引擎(因为我们无法击败CAP定理,并且通常我们希望可用)。这些系统不会通过相互轮询来同步(除了共识操作?),而是使用CRDT和事件日志等结构来使分布式系统的所有成员最终保持一致(如果有足够的时间,成员将收敛到相同的数据)。

现在想想什么是移动设备或浏览器。它只是分布式系统的一个成员,可能会遭受网络延迟和网络分区的影响。(即您在地铁上使用智能手机)

如果我们能够构建网络分区和网络速度容限数据库(我的意思是我们仍然可以对隔离的节点执行写入操作),我们可能会构建受这些概念启发的前端软件(移动或桌面),这些软件可以与开箱即用的离线模式很好地配合使用,而不会出现应用程序功能不可用。

我认为我们应该真正激发自己关于数据库如何构建我们的前端应用程序的方法。需要注意的一点是,这些应用程序不执行 POST 和 PUT 以及 GET ajax 请求来相互发送数据,而是使用事件日志和 CRDT 来确保最终的一致性。

那么为什么不在前端这样做呢?请注意,后端已经朝着这个方向发展,像Kafka这样的工具被大玩家大量采用。这也与事件溯源/ CQRS / DDD有关。

查看卡夫卡作者的这些精彩文章,以说服自己:

也许我们可以从向服务器发送命令开始,并接收服务器事件流(通过websockets进行exinmple),而不是触发Ajax请求。

我对Ajax的请求从来都不是很舒服。当我们React开发人员时,他们往往是函数式程序员。我认为很难推断本地数据应该是你的前端应用程序的“真相来源”,而真正的事实来源实际上在服务器数据库上,当你收到它时,你的“本地”事实来源可能已经过时了,除非你按下一些蹩脚的刷新按钮,否则永远不会收敛到真正的真相来源价值......这是工程吗?

然而,由于一些明显的原因,设计这样的东西仍然有点困难:

  • 您的移动/浏览器客户端资源有限,不一定能在本地存储所有数据(因此有时需要使用ajax请求繁重的内容进行轮询)
  • 您的客户端不应看到分布式系统的所有数据,因此出于安全原因,它需要以某种方式过滤它收到的事件