使用 RefreshView API 刷新组件数据

无论是用户驱动还是应用调用,在不重新加载整个页面的情况下同步数据的能力都是一项关键的用户体验要求。RefreshView API 和模块提供了一种在 LWC 和 Aura 中刷新组件数据的标准方法。lightning/refresh

RefreshView API 对刷新范围的详细控制使你能够创建精细的用户体验,同时保持向后兼容性。

RefreshView API 为您提供了更新组件层次结构(称为视图)的选项,而无需重新加载整个页面。此刷新可确保与订阅该视图中刷新事件的组件外部源的数据完全同步。RefreshView API 支持由最终用户或 Web 组件触发的刷新。RefreshView API 为 LWC 组件中的数据刷新体验提供了标准机制,允许灵活控制刷新范围。

RefreshView API 可以刷新 Salesforce 平台容器以及自定义 LWC 和 Aura 组件的数据。

Lightning 数据服务支持 RefreshView API。

使用 RefreshView API 的限制

RefreshView API 可以在已启用 Lightning Web Security 或 Lightning Locker 的组织中使用。每个安全体系结构的注册容器和处理程序的协议都不同。

基本 Lightning Aura 组件目前不支持 RefreshView API。

RefreshView API 用户体验

可靠的内容刷新是一项基本的 Web UX 要求,可以由用户驱动,也可以由应用调用。

用户触发的刷新的典型流程为:

  1. Lightning Web 组件显示一个按钮(或其他用户界面控件),用于启动一个进程,该进程将组件中显示的数据与其源同步。
  2. 点击按钮时,按钮组件将调度一个事件。RefreshEvent
  3. 向 RefreshView API 注册的最近级别的容器组件将收到 ,停止其传播。RefreshEvent
  4. 组件的刷新处理程序在相应的组件上启动刷新过程。它们可以显示微调器、执行检测以及执行其他操作来准备要刷新的 UI。
  5. 处理程序的后代组件通过公开的 API 挂钩参与刷新过程。他们可以从 Salesforce 组织获取数据或执行其他任务以将显示的数据与外部数据源同步。
  6. 当所有数据在屏幕上同步和更新时,组件层次结构的刷新完成。

对于应用触发的刷新:

  1. 应用程序确定视图需要刷新以确保数据同步。例如,在从过期会话重新进行身份验证后,或者在移动 UI 上执行下拉刷新操作后,需要刷新。
  2. 从这一点来看,刷新流类似于上面描述的用户触发刷新。

使用 RefreshView API

若要使用 RefreshView API,请导入模块。lightning/refresh

该模块还取代了 Aura 并暴露了:lightning/refreshforce:refreshView

  • 模块可以触发以发出刷新信号的事件。RefreshEvent
  • 允许组件注册以接收调度的刷新事件并开始刷新过程的方法。
  • 允许组件注册在刷新过程中调用的回调方法的方法。
  • 状态定义,如 、 和 。RefreshCompleteRefreshCompleteWithErrorRefreshError

在 LWC 中注册刷新处理程序方法

您必须注册属于启用刷新的视图的组件,以包含在刷新过程中。

若要参与视图刷新,组件需要注册一个处理程序方法。使用组件中的方法注册处理程序方法。registerRefreshHandler()connectedCallback()

重要

当组件在未启用 LWS 且仍在使用 Lightning Locker 的组织中运行时,方法中传递的参数需要不同的格式。registerRefreshHandler()

在容器收到 .已注册的容器由已注册的刷新处理程序组成“刷新树”,其顺序模拟 DOM。然后,容器调用参与者组件的回调刷新方法,这些组件已注册刷新处理程序。RefreshEvent

启用了 LWS 的组织示例

import { LightningElement } from "lwc";
import { registerRefreshHandler, unregisterRefreshHandler } from "lightning/refresh";
export default class RefreshHandler extends LightningElement {
  refreshHandlerID;
  connectedCallback() {
    this.refreshHandlerID = registerRefreshHandler(this, this.refreshHandler);
  }
  disconnectedCallback() {
    unregisterRefreshHandler(this.refreshHandlerID);
  }
  refreshHandler() {
    // example usage case for refresh participant
    // fetch some data and report status once complete
    let endPoint = "https://api.<your company>.com";
    return new Promise((resolve) => {
      fetch(endPoint, {
        method: "GET",
      });
      resolve(true);
    });
  }
}

启用了 Lightning Locker 的组织示例

import { LightningElement } from "lwc";
import { registerRefreshHandler, unregisterRefreshHandler } from "lightning/refresh";
export default class RefreshHandler extends LightningElement {
  refreshHandlerID;
  connectedCallback() {
    this.refreshHandlerID = registerRefreshHandler(
      this.template.host,
      this.refreshHandler.bind(this),
    );
  }
  disconnectedCallback() {
    unregisterRefreshHandler(this.refreshHandlerID);
  }
  refreshHandler() {
    // example usage case for refresh participant
    // fetch some data and report status once complete
    let endPoint = "https://api.<your company>.com";
    return new Promise((resolve) => {
      fetch(endPoint, {
        method: "GET",
      });
      resolve(true);
    });
  }
}

刷新树中已注册的刷新方法按广度优先的顺序从已注册容器的节点调用。此方法可确保在调用较低级别(子)处理程序之前解析较高级别(父级)处理程序。

已注册的刷新处理程序回调必须:

  • 返回解析为 a 的 a:PromiseBoolean
    • true如果组件已完成刷新操作,并且刷新过程可以从此节点继续沿刷新树向下
    • false防止刷新过程继续到此节点的子元素
  • 根据当前状态执行必要的视图更新操作。
  • 如有必要,请确保重新同步数据和状态。
  • 在此过程中显示相应的 UI,例如微调器或 Toast。

您还必须注销组件的处理程序方法,如上例所示。disconnectedCallback()

使用 RefreshEvent 发出刷新信号

要启动视图刷新,请触发 中定义的事件。此事件向容器发出请求以开始刷新过程。可以从任何组件触发此事件。RefreshEventlightning/refresh

import { LightningElement } from "lwc";
import { RefreshEvent } from "lightning/refresh";

export default class RefreshButton extends LightningElement {
  // signal a refresh programmatically
  // or via a button click
  beginRefresh() {
    this.dispatchEvent(new RefreshEvent());
  }
}

注册以接收 RefreshEvent

若要在用户视图上开始刷新过程,每个容器中的应用程序控制器必须注册才能接收 .使用容器中的方法注册以接收 .RefreshEventregisterRefreshContainer()connectedCallback()RefreshEvent

重要

当组件在未启用 LWS 且仍在使用 Lightning Locker 的组织中运行时,方法中传递的参数需要不同的格式。registerRefreshContainer()

注意

如果要将组件添加到活动页面,则无需创建容器即可接收 .仅当想要确定刷新范围时,才添加容器。RefreshEvent

启用了 LWS 的组织示例

import { LightningElement } from "lwc";
import {
  registerRefreshContainer,
  unregisterRefreshContainer,
  REFRESH_ERROR,
  REFRESH_COMPLETE,
  REFRESH_COMPLETE_WITH_ERRORS,
} from "lightning/refresh";

export default class RefreshContainer extends LightningElement {
  refreshContainerID;
  connectedCallback() {
    this.refreshContainerID = registerRefreshContainer(this, this.refreshContainer);
  }
  disconnectedCallback() {
    unregisterRefreshContainer(this.refreshContainerID);
  }
  refreshContainer(refreshPromise) {
    console.log("refreshing");
    return refreshPromise.then((status) => {
      if (status === REFRESH_COMPLETE) {
        console.log("Done!");
      } else if (status === REFRESH_COMPLETE_WITH_ERRORS) {
        console.warn("Done, with issues refreshing some components");
      } else if (status === REFRESH_ERROR) {
        console.error("Major error with refresh.");
      }
    });
  }
}

启用了 Lightning Locker 的组织示例

import { LightningElement } from "lwc";
import {
  registerRefreshContainer,
  unregisterRefreshContainer,
  REFRESH_ERROR,
  REFRESH_COMPLETE,
  REFRESH_COMPLETE_WITH_ERRORS,
} from "lightning/refresh";

export default class RefreshContainer extends LightningElement {
  refreshContainerID;
  connectedCallback() {
    this.refreshContainerID = registerRefreshContainer(
      this.template.host,
      this.refreshContainer.bind(this),
    );
  }
  disconnectedCallback() {
    unregisterRefreshContainer(this.refreshContainerID);
  }
  refreshContainer(refreshPromise) {
    console.log("refreshing");
    return refreshPromise.then((status) => {
      if (status === REFRESH_COMPLETE) {
        console.log("Done!");
      } else if (status === REFRESH_COMPLETE_WITH_ERRORS) {
        console.warn("Done, with issues refreshing some components");
      } else if (status === REFRESH_ERROR) {
        console.error("Major error with refresh.");
      }
    });
  }
}

传递 to 将事件侦听器绑定到 的元素。当已注册的刷新容器收到 时,刷新过程将在其刷新树上开始。thisregisterRefreshContainerRefreshEventRefreshEvent

注意

RefreshEvent遵循 DOM 事件冒泡规则,因此开始此过程的刷新容器是离信令组件最近的注册祖先。

在此示例中,当容器收到 .刷新过程开始时,回调接收 a 作为参数。刷新过程完成后,将使用一个值来解决此问题。refreshContainer()RefreshEventPromisePromiseRefreshStatus

若要管理与刷新相关的进程,请使用已注册容器的回调方法。例如:

  • 检测开始/结束
  • 显示微调器
  • 错误处理
  • 祝酒词

如示例中所示,在使用该方法时,还必须将视图控制器注销为刷新容器。RefreshEventdisconnectedCallback()unregisterRefreshContainer()

RefreshView API 示例

使用 RefreshView API 通常涉及一系列操作。

首先,页面上的某个位置必须有一个组件,可以在需要刷新时发送事件。在此示例中,组件可以发出刷新信号。RefreshEventrefreshButton

// refreshButton.js
import { LightningElement } from "lwc";
import { RefreshEvent } from "lightning/refresh";

export default class RefreshButton extends LightningElement {
  // signal a refresh programmatically
  // or via a button click
  beginRefresh() {
    this.dispatchEvent(new RefreshEvent());
  }
}
<!-- refreshButton.html -->
<template>
  <button label="Refresh Button" onclick={beginRefresh}>Refresh</button>
</template>

接下来,为了参与视图刷新,组件注册一个处理程序方法,以便在容器收到 .在此示例中,handler 方法在 中注册。RefreshEventrefreshHandler.js

//refreshHandler.js
import { LightningElement } from "lwc";
import { registerRefreshHandler, unregisterRefreshHandler } from "lightning/refresh";
export default class RefreshHandler extends LightningElement {
  refreshHandlerID;
  connectedCallback() {
    this.refreshHandlerID = registerRefreshHandler(this, this.refreshHandler);
    // if the component runs in an org with Lightning Locker instead of LWS, use
    // this.refreshHandlerID = registerRefreshHandler(this.template.host, this.refreshHandler.bind(this));
  }
  disconnectedCallback() {
    unregisterRefreshHandler(this.refreshHandlerID);
  }
  refreshHandler() {
    // example usage case for refresh participant
    // fetch some data and report status once complete
    let endPoint = "https://api.<your company>.com";
    return new Promise((resolve) => {
      fetch(endPoint, {
        method: "GET",
      });
      resolve(true);
    });
  }
}

最后,页面上的某个地方必须有一个组件可以注册接收。在此示例中,注册以接收刷新事件。当收到事件时,它会启动刷新过程。RefreshEventrefreshContainer

// refreshContainer.js
import { LightningElement } from "lwc";
import { registerRefreshContainer, unregisterRefreshContainer } from "lightning/refresh";

export default class RefreshContainer extends LightningElement {
  refreshContainerID;
  connectedCallback() {
    this.refreshContainerID = registerRefreshContainer(this, this.refreshContainer);
    // if the component runs in an org with Lightning Locker instead of LWS, use
    // this.refreshContainerID = registerRefreshContainer(this.template.host, this.refreshContainer.bind(this));
  }
  disconnectedCallback() {
    unregisterRefreshContainer(this.refreshContainerID);
  }
  refreshContainer(refreshPromise) {
    console.log("refreshing");
    return refreshPromise.then((status) => {
      if (status === REFRESH_COMPLETE) {
        console.log("Done!");
      } else if (status === REFRESH_COMPLETE_WITH_ERRORS) {
        console.warn("Done, with issues refreshing some components");
      } else if (status === REFRESH_ERROR) {
        console.error("Major error with refresh.");
      }
    });
  }
}

将 和 组件放在模板中,包括标记中的命名空间。 是此示例中的默认命名空间。refreshHandlerrefreshButtonrefreshContainerc

<!-- refreshContainer.html -->
<template>
  <!-- Ensure handler exists within structure of container -->
  <div>
    <c-refresh-handler></c-refresh-handler>
  </div>
  <div>
    <c-refresh-button></c-refresh-button>
  </div>
</template>

考虑

在开发使用 RefreshView API 的功能时,请记住以下几点。

  • 在处理来自第三方的 Aura 组件或数据时,请使用 RefreshView API。在这些情况下,参与 RefreshView API 的组件可以使用 notifyRecordUpdateAvailable(recordIds) 和/或 refreshApex 来刷新它们从 Lightning 数据服务接收的数据。
  • 仅为要参与刷新的组件注册回调。refresh()lightning/refresh
  • 组件不负责刷新其后代 — 后代必须注册自己的回调才能参与正常值传播之外的刷新。
  • 为了允许作用域内刷新树,容器的注册方式与想要自行刷新的组件类似。

从 Apex 调用 API

要从 Apex 调用 API,请使用命名凭据,该凭据指定标注终结点的 URL 及其所需的身份验证参数。

注意

根据安全策略,由 Lightning 组件创建的会话不会启用 API 访问。此限制甚至会阻止您的 Apex 代码对 Salesforce 进行 API 调用。通过对特定 API 调用使用命名凭据,您可以谨慎且有选择地绕过此安全限制。

对启用 API 的会话的限制并非偶然。请仔细检查使用命名凭据的任何代码,以确保不会造成漏洞。

在使用 Apex 进行 API 调用之前,请查看是否可以从 JavaScript 进行 API 调用。您可以在 JavaScript 中使用 Lightning Data Service (LDS) 来处理 Salesforce 记录的数据和元数据。Lightning Data Service 建立在公共用户界面 API 之上,但它仅支持 API 的一个子集。该子集涵盖了许多处理数据的典型用例。您无法从 JavaScript 代码调用除 LDS 之外的 Salesforce API。

如果 Lightning 数据服务不支持您要使用的实体,或者您想要使用其他 Salesforce API,请从 Apex 类调用该 API。