在 emberjs 中从组件 类 调用 API 调用是一种好方法吗?

Is it a good way to call API calls from component classes in emberjs?

我现在正在学习 emberjs,我想知道这是否是在组件 classes 的函数内发出获取请求(例如按钮点击)并将数据存储在 class 组件。例如:

export default class ExampleComponent extends Component {
  @tracked items;
  @action async toggleCall() {
    await fetch(...)
    .then(...)
  }
}

或者您在 emberjs 中以不同的方式执行此操作?

是的,这是一个非常合理的方法。

但是,你需要以某种方式手动调用toggleCall

我最喜欢在组件中加载东西或做任何事情异步的方式是使用“资源”通过派生数据懒惰地和反应性地这样做。

有一个名为 trackedFunction 的实用程序来自:https://github.com/nullvoxpopuli/ember-resources Specific docs here

您的示例可以重写为:

import Component from '@glimmer/component';
import { trackedFunction } from 'ember-resources';

export default class Example extends Component {
  fetchItems = trackedFunction(this, async () => {
    let response = await fetch( /* ... */);
    return await response.json();
  });

  get items() {
    // specify a default value of empty array when value is undefined
    // (value is undefined before the function finishes running)
    return this.fetchItems.value ?? [];
  }
}

主要区别:

  • trackedFunction 将在访问时自动调用
  • repeat-accesses 不会重新调用函数
  • trackedFunction 中的 await 之前使用的任何 @tracked 数据将“纠缠”,因此对该 @tracked 数据的更改将导致函数 运行 再次,例如,如果你有一个查询参数
  @tracked filter = 'name:starts_with=a';

  fetchItems = trackedFunction(this, async () => {
    let url = `...?${this.filter}`;
    let response = await fetch(url /* ... */);
    return await response.json();
  });

fetchItems 是反应式的,因为现在当 filter 改变时,fetchItems 会重新调用自己。


但是,如果您打算保留点击请求行为(这很常见!),您可能会对 ember-concurrency 感兴趣,它提供了一些很好的人体工程学实用程序来处理/保护您的来自使用人机交互的愚蠢行为的数据——例如在用户单击按钮后不重新请求,并在请求完成之前再次单击该按钮。

您的示例将是:

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { dropTask } from 'ember-concurrency';

export default class Example extends Component {
  @dropTask
  *fetchItems() {
    let response = await fetch( /* ... */);
    return await response.json();
  }

  get items() {
    return this.fetchItems.lastSuccessful.value ?? [];
  }

  // click handler can be called any number of times,
  // which would, in turn, call fetchItems any number of times,
  // but only one `fetch` request will ever run at a given time.
  @action
  handleClick() {
    this.fetchItems.perform();
  }
}

关于 ember-并发的文档:https://ember-concurrency.com/