首页 > 解决方案 > 如何在道具更改时取消 Cmd.OfAsync?

问题描述

假设我有一个受控的 Elmish 形式:

type Model = 
  {
    Query : string
    IsLoading : bool
    Result : Result<QueryResults, string> option
  }

type Message =
  | UpdateQuery of string
  | ReceivedResults of Result<QueryResults, string>

let update message model = 
  match message with
  | UpdateQuery query ->
    let nextModel =
      {
        model with
          Query = query
          IsLoading = true
      }

    let cmd = 
      Cmd.OfAsync.result (async {
        let! results = Api.tryFetchQueryResults query

        return ReceivedResults results
      })

    nextModel, cmd
  | ReceivedResults results ->
    {
      model with
        IsLoading = false
        Results = Some results
    }, Cmd.none

每次model.Query更改时,它都会发送一个async请求。但是,如果已经有一个请求正在进行中,我希望将其取消并替换为新请求。

在 Elmish 中执行此操作的好方法是什么?

标签: f#elmish

解决方案


没有内置支持取消基础XMLHttpRequest.

但是,我们可以构建一些支持类似取消功能的小型机器:

首先,Model使用有关当前待处理查询的信息来增加您的信息,并Message使用该查询的链接(一个简单的Guid方式)来增加您的信息

open System

type Model = 
  {
    Query : string
    IsLoading : bool
    Result : Result<QueryResults, string> option
    PendingQuery: Guid option
  }

type Message =
  | UpdateQuery of string
  | ReceivedResults of Guid * Result<QueryResults, string>

update接下来,在您的函数中提供这些数据

  | UpdateQuery query ->

    let correlationId = Guid.NewGuid()

    let nextModel =
      {
        model with
          Query = query
          IsLoading = true
          PendingQuery = Some correlationId
      }

    let cmd = 
      Cmd.OfAsync.result (async {
        let! results = Api.tryFetchQueryResults query

        return ReceivedResults (correlationId, results)
      })

    nextModel, cmd

最后,在从服务器接收数据时检查未决查询并忽略与链接不匹配的内容

  | ReceivedResults (correlationId, results) ->
    match model.PendingQuery with
    | Some id when id = correlationId ->
      {
        model with
          IsLoading = false
          PendingQuery = None
          Result = Some results
      }, Cmd.none
    | _ -> model, Cmd.none

推荐阅读