使用 Wire Service 获取数据
LWC 使用响应式 wire service 读取 Salesforce 数据。在 JS 类中用 @wire 装饰器指定 Lightning Data Service(LDS)wire adapter——adapter 定义数据形状,wire service 以不可变流方式提供数据。优先使用返回最少数据的 adapter 以提升性能。先用 lightning-record*form 组件检查是否有更简单的方式。
Wire Service 语法与 @salesforce/schema 导入
import { adapterId } from 'adapterModule';
@wire(adapterId, adapterConfig) propertyOrFunction;
// 导入对象和字段引用(强烈推荐——编译时验证/防删除/级联重命名)
import ACCOUNT_OBJECT from "@salesforce/schema/Account";
import ACCOUNT_NAME_FIELD from "@salesforce/schema/Account.Name";
import OWNER_NAME from "@salesforce/schema/Account.Owner.Name"; // 最多3层关系字段
// 配置对象:$前缀 = 动态响应式属性
@wire(getRecord, { recordId: "$recordId", fields: [ACCOUNT_NAME_FIELD] }) record;
@salesforce/schema 导入优势:Salesforce 验证对象和字段存在、防止被删除、重命名时级联更新源码、确保变更集和包包含依赖。命名惯例:OBJECTNAME_OBJECT、FIELDNAME_FIELD(指南非规则)。
复合字段规则:读取可用复合字段(如 Contact.Name);创建和更新必须用独立字段(Contact.FirstName + Contact.LastName)。地址和地理定位字段仅通过字符串语法访问独立字段。
导入限制:仅支持标准对象和自定义对象(__c)。Person Account __pc → 从 Contact 导入对应自定义字段。外部对象 __x → 通过 Apex SOQL 获取。Knowledge__kav → 用字符串语法 'Knowledge__kav.Title'。
响应式 $ 前缀 —— 动态配置
配置对象中值前加 $ 前缀 → 引用组件实例属性(this.propertyName)→ 响应式:属性值变化时 wire service 重新提供新数据,组件重渲染。
@api recordId;
@wire(getRecord, { recordId: "$recordId", fields }) account;
// $recordId 动态响应式——recordId 变化时自动重新获取
// fields 是静态值——不变化
// 支持三种动态属性:私有属性、getter-setter 属性、@api 属性
// $ 只能用于顶层值——嵌套在数组中如 ['$ids'] 变成字面字符串!
不带 $ 的值是静态的——不随组件状态变化。可以用一个 @wire 输出作为另一个 @wire 输入——如 $record.data.fieldName。
装饰属性 vs 装饰函数
装饰属性(消费数据原样):结果返回到属性的 data/error 子属性。初始默认值 { data: undefined, error: undefined }。数据可用时设 data(error=undefined)→ 新版本数据到达时更新 data。错误时设 error(data=undefined)。
@wire(getRecord, { recordId: "$recordId", fields: [NAME] }) record;
// record.data → 数据可用时填充 | record.error → 错误时填充
// 模板中用 lwc:if={record.data} 检查
装饰函数(需要处理逻辑):每次新数据提供或错误发生时调用。参数对象含 data 和 error(顺序无关——因为是解构对象)。调用时机可能在连接或渲染之前或之后。
@wire(getRecord, { recordId: "$recordId", fields })
wiredAccount({ data, error }) {
if (data) { this.record = data; this.error = undefined; }
else if (error) { this.error = error; this.record = undefined; }
}
选择指南:属性——简单消费数据;函数——需要转换、错误处理、或派生状态的逻辑。
Wire Service 数据生命周期
Wire adapter 仅在配置完整时(所有动态参数有值)才被评估——如果参数依赖父组件 wire 结果,可能需要等待。
生命周期顺序:constructor() → 配置完整 → 默认值 provision({data:undefined, error:undefined})→ connectedCallback() → render() → renderedCallback() → 数据到达(data 填充)→ render() + renderedCallback() 再次触发。
关键原则:
- LDS wire 可以在配置不变的情况下多次 emit 数据——LDS 控制这些 emit,与 LWC 生命周期无关
- Wire adapter 调用是异步的(除非数据已缓存)——响应和 Promise 解析顺序不保证
- 不要在特定生命周期点依赖数据到达——wire 可以在任何时候接收数据
- 数据在 LDS 缓存中已存在时无网络调用直接返回
- Apex trigger 或 auto-launched flow 异步变更记录 → wire adapter 不会重新评估
- 手动刷新:Apex wire →
refreshApex();GraphQL wire →refreshGraphQL()。不要用 setTimeout/setInterval 轮询——造成不必要服务器负载
获取记录数据 —— 实战示例
完整示例——从 Contact 记录获取 Name/Title/Phone/Email 并用 lightning-formatted-* 组件显示:
// JS
import { getRecord } from "lightning/uiRecordApi";
const FIELDS = ["Contact.Name", "Contact.Title", "Contact.Phone", "Contact.Email"];
@api recordId; // 记录页面自动提供
@wire(getRecord, { recordId: "$recordId", fields: FIELDS }) contact;
get name() { return this.contact.data.fields.Name.value; }
get phone() { return this.contact.data.fields.Phone.value; }
// HTML —— lwc:if 守卫防止 data 为 undefined 时报错
<template lwc:if={contact.data}>
<p>{name}</p>
<lightning-formatted-phone value={phone}></>
</template>
<template lwc:if={contact.error}>
<c-error-panel errors={contact.error}></>
</template>
返回数据结构与 UI API 的 Record 响应 相同。推荐用 getFieldValue(record, field) 简化数据访问——替代 this.contact.data.fields.Name.value。
处理 Lightning Data Service 错误
LDS wire adapter 在资源不可访问时返回错误——无效 ID、缺失字段、记录被删除/共享变更、缓存中无数据且服务器离线。
异步代码错误处理陷阱:try-catch 只能捕获同步代码中的异常——setTimeout 回调中的错误在 try-catch 外部。必须在回调函数内部使用 try-catch。
Wire 函数中的错误处理模式:
@wire(getRecord, { recordId: "$recordId", fields })
wiredRecord({ error, data }) {
if (data) {
try { /* 处理结果 */ } catch(e) { /* 处理结果时出错 */ }
} else if (error) {
// 值供应时出错
this.error = Array.isArray(error.body)
? error.body.map(e => e.message).join(', ')
: error.body.message;
this.record = undefined;
}
}
错误响应结构:{ status, body:{message,statusCode,errorCode}, ok:false, statusText, errorType:"fetchResponse" }。Body 格式取决于 API:UI API 读 → 数组;UI API 写 → 对象(含对象级和字段级错误);Apex → 对象;网络错误 → 对象。Wire 首次触发前 data 和 error 都是 undefined——这不是错误状态,只是尚未触发。参考 lwc-recipes ldsUtils 工具函数。
Wire Service 搭配基础组件
当 lightning-record*form 不够灵活时,使用 wire service + 基础组件构建自定义 UI。
输入组件:lightning-input(通用输入)、lightning-combobox(下拉选择)、lightning-input-name(姓名复合字段)、lightning-input-address(地址)、lightning-textarea(多行文本)、lightning-radio-group/lightning-checkbox-group(选择组)。
显示组件:lightning-formatted-name/address/phone/email/number/date-time/text/url/rich-text/time——根据字段类型选择对应的格式化显示组件。
实战——自定义表单(姓名 + 称谓):getRecord 获取 FirstName/LastName/Salutation 字段值;getPicklistValues 获取称谓选项列表(需 recordTypeId + fieldApiName);lightning-input-name 绑定三个属性 + options 数组。
实战——带地图的地址显示:getRecord 获取 MailingStreet/City/State/Country/PostalCode;lightning-formatted-address 绑定各字段 + show-static-map 属性——点击地址或地图在新标签打开 Google Maps。
感谢阅读本指南。如需继续学习,请参阅下一章:跨 LWC 组件管理状态。