我们想一个场景,一个详情页面包含了LDS的组件,包含了基于 apex的获取的数据的组件,当LDS使用了 inline edit编辑了数据,LDS会获取最新数据,那通过 apex获取的数据没法自动更新的,反之也相同,基于apex进行了当前数据进行更新,但是LDS和这个不共用缓存,那LDS相关的组件也不会自动更新,这种基于缓存问题导致的UI数据不同步在实际项目中是灾难的,如何进行规避或者处理呢?
我们先以一个例子更好的了解上述情况的一个表象。
RecordNotifyChangeController.cls
public with sharing class RecordNotifyChangeController {
@AuraEnabled
public static String saveAccount(String recordId,String industry,String phone) {
Account accountItem = new Account();
accountItem.Id = recordId;
accountItem.industry = industry;
accountItem.phone = phone;
accountItem.Name = industry + phone;
try {
update accountItem;
return 'success';
} catch(Exception e) {
return 'error';
}
}
@AuraEnabled(cacheable=true)
public static Account getAccount(String recordId) {
Account accountItem = [SELECT Name,Industry,Phone from Account where Id = :recordId limit 1];
return accountItem;
}
}
recordNotifyChangeSample.js
import { LightningElement, wire,api,track } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
import { refreshApex } from '@salesforce/apex';
import saveAccount from '@salesforce/apex/RecordNotifyChangeController.saveAccount';
import getAccount from '@salesforce/apex/RecordNotifyChangeController.getAccount';
import PHONE_FIELD from '@salesforce/schema/Account.Phone';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
import NAME_FIELD from '@salesforce/schema/Account.Name';
export default class RecordNotifyChangeSample extends LightningElement {
@api recordId;
@track phone;
@track industry;
@track accountName;
fields=[PHONE_FIELD,INDUSTRY_FIELD];
accountRecord;
@wire(getAccount,{recordId : '$recordId'})
wiredAccount(value) {
this.accountRecord = value;
const { data, error } = value;
if(data) {
this.industry = data.Industry;
this.phone = data.Phone;
this.accountName = data.Name;
}
}
handleChange(event) {
if(event.target.name === 'phone') {
this.phone = event.detail.value;
} else if(event.target.name === 'industry') {
this.industry = event.detail.value;
}
}
handleSave() {
saveAccount({ recordId: this.recordId, industry : this.industry, phone : this.phone})
.then(result => {
if(result === 'success') {
//TODO
} else {
//TODO
}
})
.catch(error => {
//TODO
});
}
}
recordNotifyChangeSample.html
<template>
<lightning-card title="use lightning-record-form">
<lightning-record-form object-api-name="Account" fields={fields} record-id={recordId} mode="view"></lightning-record-form>
</lightning-card>
<lightning-card title="use lightning input">
<lightning-layout multiple-rows="true">
<lightning-layout-item size="12">
<lightning-input value={accountName} label="Name"></lightning-input>
</lightning-layout-item>
<lightning-layout-item size="6">
<lightning-input value={phone} label="Phone" name="phone" onchange={handleChange}></lightning-input>
</lightning-layout-item>
<lightning-layout-item size="6">
<lightning-input value={industry} name="industry" label="Industry"></lightning-input>
</lightning-layout-item>
<lightning-layout-item size="12">
<lightning-button onclick={handleSave} label="save"></lightning-button>
</lightning-layout-item>
</lightning-layout>
</lightning-card>
</template>
我们将上述的demo放在account详情页面,在下方修改了 Phone的值点击Save以后,理论上后台调用的方法会将Name信息变成 Industry + Phone,但是我们会发现上面的使用LDS的组件以及下方使用wire方式调用后台的内容都没有被自动更新,这就是前端缓存场景的危害。
针对lightning下的缓存处理,官方有两个缓存处理的方式。
仅针对调用apex方式交互的wire场景(强制调用方式此方法不生效),apex方法需要强制使用 cacheable=true,当上述场景,会产生问题。官方通过 refreshApex方法,调用以后会通知浏览器当前wire对应方法调用的数据不是最新的,需要重新调用后台方法获取最新的数据。refreshApex使用通常两个步骤。
import { refreshApex } from '@salesforce/apex';
refreshApex(valueProvisionedByApexWireService);
valueProvisionedByApexWireService绑定的是通过wire apex方式返回的变量,如果wire apex返回结果基于函数方式,我们基于参数可以作为这个变量。实际项目中基于可扩展性,推荐函数方式后绑定。
通知LDS记录数据已经改变,这样LDS就可以采取适当的行动,使线程适配器更新最新的记录数据。notifyRecordUpdateAvailable的使用通常两个步骤:
import { notifyRecordUpdateAvailable } from 'lightning/uiRecordApi';
notifyRecordUpdateAvailable(items: Array<{recordId: string}>);