我们想一个场景,一个详情页面包含了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方式调用后台的内容都没有被自动更新,这就是前端缓存场景的危害。

Untitled

针对lightning下的缓存处理,官方有两个缓存处理的方式。

一. refreshApex

仅针对调用apex方式交互的wire场景(强制调用方式此方法不生效),apex方法需要强制使用 cacheable=true,当上述场景,会产生问题。官方通过 refreshApex方法,调用以后会通知浏览器当前wire对应方法调用的数据不是最新的,需要重新调用后台方法获取最新的数据。refreshApex使用通常两个步骤。

  1. 头部引入import { refreshApex } from '@salesforce/apex';
  2. refreshApex(valueProvisionedByApexWireService);

valueProvisionedByApexWireService绑定的是通过wire apex方式返回的变量,如果wire apex返回结果基于函数方式,我们基于参数可以作为这个变量。实际项目中基于可扩展性,推荐函数方式后绑定。

二. notifyRecordUpdateAvailable

通知LDS记录数据已经改变,这样LDS就可以采取适当的行动,使线程适配器更新最新的记录数据。notifyRecordUpdateAvailable的使用通常两个步骤:

  1. 头部引入import { notifyRecordUpdateAvailable } from 'lightning/uiRecordApi';
  2. notifyRecordUpdateAvailable(items: Array<{recordId: string}>);