应在哪里发起HTTP请求?

时间:2015-04-26 09:18:40

标签: reactjs reactjs-flux flux

如何与Flux中的外部服务进行通信,plenty discussion。{/ p>

很明显,基本工作流程是触发HTTP请求,最终会根据响应调度成功或失败操作。您也可以选择发送"进行中"在提出请求之前采取行动。

但是,如果请求的参数取决于商店的状态呢?似乎没有人提到它。

基本上,根据用户与视图的交互,调度ACTION。 Store拥有关于如何在给定ACTION的情况下从当前state0转换到下一个state1的逻辑。需要来自state1的数据才能正确形成新的HTTP请求。

例如,用户在页面上选择一个新过滤器,而商店决定也重置分页。这应该会导致新的HTTP请求(新的过滤器值,第一页),而不是(新的过滤器值,来自state0的当前页面)。

View无法通过用户的交互使HTTP调用本身正确,因为它必须复制商店的逻辑才能转换到下一个状态。

View无法在其商店的onChange处理程序中进行HTTP调用,因为此时不再知道状态更改的来源是什么。

在转换到下一个状态后,在动作处理程序中使存储触发HTTP请求看起来是一个可行的选项。但是这会使这个动作隐式启动HTTP调用,这会禁止为调试提供可重放的调度操作日志。

在Flux中应该在哪里发起HTTP请求?

2 个答案:

答案 0 :(得分:1)

让我们从底部开始:

  

在转换到下一个状态后,在动作处理程序中使存储触发HTTP请求看起来是一个可行的选项。但是这会使这个动作隐式启动HTTP调用,这会禁止为调试提供可重放的调度操作日志。

如果您处于调试/重播模式,则可以通过不启动HTTP请求来缓解此问题。只要您在HTTP请求处理程序中执行唯一操作是火灾操作(例如SUCCESSFAILURE操作),这就非常有用。您可以使用简单的全局布尔值(if (!debug) { httpReq(...) })来实现它,但您也可以使模式更正式。

Event Sourcing用语中,您将Gateways用于此目的。在正常操作中,网关发出您的HTTP请求,在调试中,您关闭网关(因此它不会发出任何HTTP请求)。

那就是说,我认为问题实际上可以通过重新考虑你的HTTP请求的位置来解决。

  

基本上,根据用户与视图的交互,调度ACTION。 Store拥有关于如何在给定ACTION的情况下从当前state0转换到下一个state1的逻辑。需要来自state1的数据才能正确形成新的HTTP请求。

在您问题的第二个链接(Where should ajax request be made in Flux app?)中,I recommend在行动创作者中进行写作,但商店中读取。如果您将该模式推断到您的用例中,您可能会得到类似这样的内容(为了清晰起见,伪代码和长变量名称):

class DataTable extends React.Component {
  render() {
    // Assuming that the store for the data table contains two sets of data:
    // one for the filter selection and one for the pagination.
    // I'll assume they're passed as props here; this also assumes that
    // this component is somehow re-rendered when the store changes.
    var filter = this.props.filter;
    var start = this.props.start;
    var end = this.props.end;

    var data = this.props.dataTableStore.getDataForPageAndFilter(
      start, end, filter
    );

    // the store will either give us the LOADING_TOKEN,
    // which indicates that the data is still loading,
    // or it will give us the loaded data
    if (data === DataTableStore.LOADING_TOKEN) {
      return this.renderLoading();
    } else {
      return this.renderData(data);
    }
  }
}

class DataTableStore {
  constructor() {
    this.cache = {};
    this.filter = null;
    this.start = 0;
    this.end = 10;
  }

  getDataForPageAndFilter(start, end, filter) {
    var url = HttpApiGateway.urlForPageAndFilter(start, end, filter);

    // in a better implementation, the HttpApiGateway
    // might do the caching automatically, rather than
    // making the store keep the cache
    if (!this.cache[url]) {
      this.cache[url] = DataTableStore.LOADING_TOKEN;

      HttpApiGateway.query(url)
      .then((response) => {
        // success
        var payload = {
          url: url,
          data: response.body
        };
        dispatch(DATA_FETCH_SUCCESS, payload);
      }, (error) => {
        // error
        dispatch(DATA_FETCH_FAIL, { ... });
      });
    }

    return this.cache[url];
  }

  handleChangeFilterAction(action) {
    this.filter = action.payload.filter;
    // the store also decides to reset pagination
    this.start = 0;
    this.end = 10;
    this.emit("change");
  }

  handleDataFetchSuccessAction(action) {
    this.cache[action.payload.url] = data;
    this.emit("change");
  }

  handleDataFetchFailAction(action) {
    // ... 
  }
}

DataTableStore.LOADING_TOKEN = "LOADING"; // some unique value; Symbols work well

您可以看到商店负责决定如何更新分页和过滤器变量,但不负责决定何时应该发出HTTP请求。相反,视图只是请求一些数据,如果商店没有在缓存中,它将然后发出HTTP请求。

这也允许视图将任何其他本地状态传递到getter中(如果HTTP请求也依赖于本地状态)。

答案 1 :(得分:0)

我不确定理解问题的所有部分,但会尝试回答一些有用的见解。

Flux有点像前端开发人员尚未成熟的EventSourcing / CQRS / Domain-Driven-Design版本

我们在后端使用类似于Flux的东西,使用不同的术语。我们可以将 Flux ActionCreators与DDD命令 Flux操作与DDD事件进行比较。

命令表示用户意图(LOAD_TIMELINE(过滤器))。最终会发布一些事件的命令处理程序可以接受或拒绝它。在UI中,拒绝命令并没有多大意义,因为您不希望显示用户不应该单击的按钮...

事件代表发生的事情(总是在过去)。

驱动UI的React应用程序状态然后以某种方式将事件日志投影到json状态。如果没有首先触发事件,UI上不会显示任何内容。

回答您的问题

  

但是,如果请求的参数依赖于商店的状态呢?似乎没有人   提到它。

在DDD中,命令处理程序实际上可以是有状态的。他们可以使用app状态来了解如何正确处理命令。不知何故,这意味着您的Flux ActionBuilders也可以是有状态的(也许他们可以使用一些商店数据)

  

基本上,基于用户与视图的交互,ACTION就是   出动。 Store拥有如何从当前状态0转换的逻辑   给予ACTION下一个state1。需要来自state1的数据   正确形成新的HTTP请求。

在DDD中有一个名为 Saga (或进程管理器)的概念。 为简单起见,它接收事件流并可以生成新命令。

所以基本上你可以通过Saga表达你的要求:当有一个事件“FILTERS_UPDATED”时,用新的过滤器发出命令“RELOAD_LIST”。我很确定你可以用任何Flux实现类似的东西。

当您重播事件日志时,应该禁用Sagas,因为重放事件日志不应具有触发新事件等副作用。

我的Atom-React框架支持这些语义,其中商店可以充当有状态的命令处理程序或传奇。