引入本篇知识以前,我们先思考一个问题。Lightning中针对数据的详情页面,一个页面可能包含了多个components针对当前表的字段展示和编辑,我们是不可能针对每一个组件都进行搜索,然后显示或者编辑的。因为如果我们针对每个component都在init操作时后台SQL进行查询,然后赋值给前台变量,进行CUD操作时,还要考虑其他component的数据是否要级联的改变,这种操作以及设计对于性能的影响还是蛮大的,有什么好的方法可以做到一次搜索或者一次加载,所有的components都共用当前的缓存内容吗?这个时候,LDS或许可以是你想要的。

在Lightning Data Service(LDS)中加载的记录被缓存并在各组件间共享。如果一个页面由显示相同记录的组件组成,所有组件都显示相同版本的记录。访问同一记录的组件可以看到显著的性能改善,因为一个记录只被加载一次,无论有多少组件在使用它。这里说的只是一个概念,大家可能好奇我使用什么组件或者什么行为,系统会认为你当前使用的是LDS,可以享受相同缓存的内容。官方针对LDS目前由两部分构成。

  1. 组件:当你使用 lightning-record-form / lightning-record-edit-form / lightning-record-view-form这三个中的一个时,系统会识别你使用LDS中的缓存,当同样是LDS因为记录更新以后,系统会自动获取最新的版本,所有使用这三个组件的组件部分将会自动更新。
  2. lightning/ui*Api下的所有的wire adapter方法,主要功能是对表数据的CRUD,对表指定视图列表数据获取,获取表schema信息等。我们以项目中常用的几个进行简单描述,其他的可以查看官方文档:https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_ui_api
    1. getRecord:使用这个wire adapter用来获取一条记录信息

      使用getRecord这个wire adapter,需要遵循以下的步骤:

      1. 头部引入getRecord →import { getRecord } from 'lightning/uiRecordApi';

      2. 使用 wire注解,头部需要引入wire。import { LightningElement,wire } from 'lwc';基于以下的两种语句格式进行获取,其中 recordId必填, fields / layoutTypes其中有一个必填并且只需要一个属性,不同时用。

        @wire(getRecord, { recordId: string, fields: string|string[], optionalFields?: string|string[] })
        propertyOrFunction
        
        @wire(getRecord, { recordId: string, layoutTypes: string|string[],
                           modes?: string|string[], optionalFields?: string|string[] })
        propertyOrFunction
        
    2. getFieldValue:在基于getRecord情况下返回指定字段的值。当我们使用 getRecord时,返回结果的结构为:record.data.fields.fieldName.value ,可以直接调用getFieldValue(record, field)获取字段值。

    3. createRecord:使用此wire adapter创建一条记录。

    4. updateRecord:使用此wire adapter修改一条记录。

    5. deleteRecord:使用此wire adapter删除一条记录。

我们以一个例子融合一下LDS的两种方式来看一下公用缓存的效果。

myComponentWithViewRecord.html:使用 lightning-record-form实现Account表的查看的组件

<template>
    <lightning-record-form
        record-id={recordId}
        object-api-name="Account"
        layout-type="Compact"
        mode="view">
    </lightning-record-form>
</template>

myComponentWithViewRecord.js

import { LightningElement, api, wire } from 'lwc';

export default class myComponentWithViewRecord extends LightningElement {
	@api recordId;
}

myComponentWithRecordEdit.html:使用 lightning-record-form实现Account表的编辑的组件

<template>
    <lightning-record-form
        record-id={recordId}
        object-api-name={objectApiName}
        fields={fields}
        columns="2"
        mode="edit"
        onsubmit={handleSubmit}
        onsuccess={handleSuccess}
        onerror={handleError}
        oncancel={handleCancel}
        onload={handleLoad}
        >
    </lightning-record-form>
</template>

MyComponentWithRecordEdit.js

/* eslint-disable no-console */
import { LightningElement, api } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

import NAME_FIELD from '@salesforce/schema/Account.Name';
import REVENUE_FIELD from '@salesforce/schema/Account.AnnualRevenue';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';

export default class MyComponentWithRecordEdit extends LightningElement {
    // The record page provides recordId and objectApiName
    @api recordId;
    @api objectApiName;

    fields = [NAME_FIELD, REVENUE_FIELD, INDUSTRY_FIELD];

    handleLoad(event) {
        console.log('execute handle load');
    }

    handleSubmit(event){
        console.log('execute handle submit');
        event.preventDefault();       // stop the form from submitting
        const fields = event.detail.fields;
        fields.LastName = 'My Custom Last Name'; // modify a field
        this.template.querySelector('lightning-record-form').submit(fields);
    }

    handleSuccess(event) {
        console.log('execute handle success');
        const evt = new ShowToastEvent({
            title: "Account Operated",
            message: "Record ID: " + event.detail.id,
            variant: "success"
        });
        this.dispatchEvent(evt);
    }

    handleError(event) {
        console.log('execute handle error');
        const evt = new ShowToastEvent({
            title: "Account Operated",
            message: event.detail.message,
            variant: "error"
        });
        this.dispatchEvent(evt);
    }

    handleCancel(event) {
        console.log('execute handle cancel')
        const evt = new ShowToastEvent({
            title: "Account canceled",
            variant: "cancel"
        });
        this.dispatchEvent(evt);
    }
}

myComponentWithRecordView.html:使用lightning-record-view-form实现Account表的查看的组件

<template>
    <lightning-record-view-form
                record-id={recordId}
                object-api-name="Account">
        <div class="slds-grid">
            <div class="slds-col">
                <lightning-output-field field-name="Name"></lightning-output-field>
            </div>
            <div class="slds-col">
                <lightning-output-field field-name="Phone"></lightning-output-field>
            </div>
            <div class="slds-col">
                <lightning-output-field field-name="AnnualRevenue"></lightning-output-field>
            </div>
            <div class="slds-col">
                <lightning-output-field field-name="Industry"></lightning-output-field>

            </div>
        </div>
    </lightning-record-view-form>
</template>

myComponentWithRecordView.js

import { LightningElement, api, wire } from 'lwc';

export default class myComponentWithRecordView extends LightningElement {
	@api recordId;
}

myComponentWithEditRecord.html:使用lightning-record-edit-form实现Account表的编辑的组件

<template>
    <lightning-record-edit-form
        record-id={recordId}
        object-api-name={objectApiName}
        onsubmit={handleSubmit}
        onload={handleLoad}
        onsuccess={handleSuccess}
        onerror={handleError}
        >
        <lightning-messages></lightning-messages>
        <lightning-input-field field-name="Name"></lightning-input-field>
        <lightning-input-field field-name="Industry"></lightning-input-field>
        <lightning-input-field field-name="AnnualRevenue"></lightning-input-field>
        <div class="slds-m-top_medium">
            <lightning-button class="slds-m-top_small" label="Cancel" onclick={handleReset}></lightning-button>
            <lightning-button class="slds-m-top_small" type="submit" label="Save Record"></lightning-button>
        </div>
    </lightning-record-edit-form>
</template>