获取数据作为对 MobX 中可观察数组变化的反应

Fetching data as reaction to observable array change in MobX

假设我们有一个可观察的主对象数组,以及关于该数组的可观察数据(例如,假设我们有 selectedReportsreportParameters)。现在假设我们发出操作以将 report 添加到数组或从该数组中删除 report。我们如何 运行 获取 reportParameters 的数据作为反应?

到目前为止,我的尝试是这样的:

// report parameters stuff
async fetchAllReportParameters() {
    reaction(
        () => this.selectedReports,
        async (reports) => {
            // reset the report parameters
            this.reportParameters = {}
            // fetch the parameters for all the reports
            await reports
                .forEach((report) => { 
                this.fetchReportParameters(report.Id)
            })
        }
    )
}
/**
 * fetches report parameters for a reportId
 * @param {number} reportId 
 */
fetchReportParameters = (reportId) => {
    this.reportParameters[reportId] = []

    const onSuccess = (reportParameters) => {
        this.reportParameters[reportId] = reportParameters
    }

    this.api.GetReportParameters(reportId)
        .then(onSuccess, this.fetchReportParametersError)


}

fetchReportParametersError = (error) => { 
    // TODO: output some error here
}

你真的打电话给 fetchAllReportParameters 吗?如果不这样做,将永远不会产生反应。您可能更喜欢从构造函数创建 reaction,假设您始终希望它是 运行。一个例子:

class SomeStore {
  constructor() {
    this.disposeReportsReaction = reaction(
      () => this.selectedReports.slice(),
      reports => {
        // ...
      }
    )
  }
}

每当您完成反应时,请致电 storeInstanceName.disposeReaction()

请注意,我在这里使用了 .slice()。这是因为如果您只是传递数组引用,则永远不会调用反应。请参阅 reaction docs:您必须以某种方式实际使用该值。

您还需要稍微调整一下异步代码。这个:

  async (reports) => {
    await reports.forEach((report) => {
      // ... 
    })
  }

不会如你所愿,因为forEach returns undefined。即使您将 async 关键字转移到 forEach 回调,所有 API 请求也会快速连续发送。考虑使用类似这样的方法,具体取决于您是否要在发送下一个请求之前等待前面的请求:

try {
  for (const report of reports) {
    await this.fetchReportParameters(report.id)
  }
} catch (e) {
  // handle error
}

这并不总是正确的答案:有时可以快速连续发送一堆请求(也许特别是如果它是小批量的,and/or 在 HTTP/2 的上下文中) .如果您不介意,您可以使用:

  reports => {
    // ...
    reports.forEach(report => this.fetchReportParameters(report.id))
  }