【Salesforce】【lwc】@api @track @wire
一、lwc中的js文件里,变量前什么也不加和加@api @track @wire有什么不同
1.单纯变量(变量a)和变量前加@track后(@track 变量a)的区别:如果是单纯值类型(比如类型:String,num, boolean)的变量, 等同于加@track后的效果,但如果是其他类型变量比如引用类型-Object(对象),那么Object(对象)中如果有值变化,调用这个引用类型Object(对象)的地方值是无法实时同步的,
但是如果在引用类型前加上@track,调用这个引用类型Object(对象)的地方值可以实现实时同步的效果,即变量前加@track后,及时是引用类型,引用类型内部的值可以被实时监控到。
2.@track:注解private类型的reactive变量。(例如lwc中,组件A(组件A中定义了带@api标识的变量a,形式即@api a,pricate类型可以理解为变量a在组件A内侧,不可以被其他组件发现、引用及赋值))。
3. @api:注解public类型的reactive变量(例如lwc中,组件A(组件A中定义了带@api标识的变量a,形式即@api a,public类型可以理解为变量a暴露在组件A外侧,可以被其他组件发现、引用及赋值),组件B可以引用组件A并可以给变量a赋值)。
4. @wire:我们常用的注解除了@track 以及 @api以外,还会经常使用@wire,区别为前两个是只针对前台的,wire既可以用在前台也可以用在后台,可以用来获取数据,创建数据,调用apex等等。
-----------------------------------------------------------
二、官网的定义如下:
引入url:https://trailhead.salesforce.com/content/learn/modules/lightning-web-components-basics/create-lightning-web-components?trail_id=build-lightning-web-components&trailmix_creator_id=sakthivel&trailmix_slug=lightning-web-component-lwc
JavaScript 中经常使用装饰器来修改属性或函数的行为。
要使用装饰器,请从lwc
模块导入它并将其放置在属性或函数之前。
您可以导入多个装饰器,但单个属性或函数只能有一个装饰器。例如,一个属性不能有@api
和@wire
装饰器。
Lightning Web 组件装饰器的示例包括:
- @api:将字段标记为公共。公共属性定义组件的 API。在其 HTML 标记中使用该组件的所有者组件可以访问该组件的公共属性。所有公共属性都是反应性的,这意味着框架会观察属性的变化。当属性的值发生变化时,框架会做出反应并重新呈现组件。
- @track:告诉框架观察对象属性或数组元素的更改。如果发生更改,框架将重新呈现组件。所有字段都是反应性的。如果字段的值发生更改并且该字段在模板中使用(或在模板中使用的属性的 getter 中),则框架将重新呈现组件。您不需要用 来装饰该字段
@track
。@track
仅当字段包含对象或数组并且您希望框架观察对象属性或数组元素的更改时才使用。如果您想更改整个属性的值,则不需要使用@track
. - @wire:为您提供一种从 Salesforce 组织获取和绑定数据的简单方法。
三、@api @track @wire的代码例子:
@api
1 // howToUseVariables.js 2 import { LightningElement, api } from 'lwc'; 3 export default class howToUseVariables extends LightningElement { 4 @api 5 age; 6 }
<!-- howToUseVariables.html --> <template> <lightning-card class="slds-m-around_small"> (@api) <p>age : {age}</p> </lightning-card> </template>
-------------------------------------------------------------------------
1 // parent.js 2 export default class parent extends LightningElement { 3 @api 4 age; 5 6 handleChanges(e){ 7 age = e.target.value; 8 } 9 }
1 <!-- parent.html --> 2 <template> 3 <c-how-to-use-variables age={age}></c-how-to-use-variables> 4 <lightning-input type="number" default=40 onchange={handleChanges} label="age"></lightning-button> 5 </template>
表示
@api を用いると、外部に変数や関数を公開することができます。
この例のように、親のコンポーネントが、公開された変数に値を入力することができます。
@track
@track
1 // howToUseVariables.js 2 import { LightningElement, track } from 'lwc'; 3 export default class howToUseVariables extends LightningElement { 4 @track 5 parsonObj = { 6 name : 'オブジェ太郎', 7 age : 123 8 }; 9 10 @track 11 parsonObjList = [ 12 {name : 'リスト太郎', age : '40'}, 13 {name : 'リスト次郎', age : '30'}, 14 {name : 'リスト三郎', age : '20'}, 15 ]; 16 17 handleChange = function(e){ 18 this.parsonObj.age = e.target.value; 19 this.parsonObjList[0].age = e.target.value; 20 } 21 }
1 <!-- howToUseVariables.html --> 2 <template> 3 <lightning-card class="slds-m-around_small"> 4 (@track - Object) 5 <div class="slds-box"> 6 <p>name : {parsonObj.name}</p> 7 <p>age : {parsonObj.age}</p> 8 </div> 9 10 (@track - Array) 11 <template for:each={parsonObjList} for:item="parsonObj"> 12 <div key={parsonObj.name} class="slds-box"> 13 <p>name : {parsonObj.name}</p> 14 <p>age : {parsonObj.age}</p> 15 </div> 16 </template> 17 18 <form> 19 <lightning-input type="number" default=40 onchange={handleChange}> 20 </lightning-input> 21 </form> 22 </lightning-card> 23 </template>
表示
このサンプルでは、「オブジェクト」「配列」に対して @track を使ってみました。
以前は、@track を使わないと、変数の変更時に再描画が行われませんでしたが、
Spring’20 の更新以降は、@track をつけなくても、再描画がされるようになっています。
しかし、オブジェクトや配列の子要素に変更を加えた場合の再描画は、@track を付けないと行われません。
そのため、このサンプルでは オブジェクトと配列を扱いました。
上記の画像は、入力欄 に99を入力したあとの状態です。handleChanges()
によってオブジェクトとリストの子要素の値が変更し、画面に反映されているのが分かると思います。
@wire
@wireの3つの方法
用法1:通过官方提供的接口uiRecordApi取数据
1 import { LightningElement, wire } from 'lwc';
2 import { getRecords } from 'lightning/uiRecordApi';
3
4 @wire(getRecords, { records: [ { recordIds: string[], fields: string[] } ] })
5 propertyOrFunction
6
7 @wire(getRecords, { records: [ { recordIds: string[], fields: string[], optionalFields?: string[] } ] })
8 propertyOrFunction
知识点引入url:https://developer.salesforce.com/docs/platform/lwc/guide/reference-wire-adapters-records.html
用法2:通过schema取数据
1 import { LightningElement, wire } from "lwc";
2 import { getRecords } from "lightning/uiRecordApi";
3 import USER_NAME_FIELD from "@salesforce/schema/User.Name";
4 import USER_EMAIL_FIELD from "@salesforce/schema/User.Email";
5 import ACCOUNT_NAME_FIELD from "@salesforce/schema/Account.Name";
6
7 export default class GetRecordsExample extends LightningElement {
8 @wire(getRecords, {
9 records: [
10 {
11 recordIds: ["005XXXXXXXXXXXXXXX"],
12 fields: [USER_NAME_FIELD],
13 optionalFields: [USER_EMAIL_FIELD],
14 },
15 {
16 recordIds: ["001XXXXXXXXXXXXXXX"],
17 fields: [ACCOUNT_NAME_FIELD],
18 },
19 ],
20 })
21 wiredRecords;
22 }
用法3:wire通过调用后台方法取掉用data
1 import { LightningElement, wire } from 'lwc';
2 import NAME_FIELD from '@salesforce/schema/Account.Name';
3 import REVENUE_FIELD from '@salesforce/schema/Account.AnnualRevenue';
4 import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
5 import getAccounts from '@salesforce/apex/AccountController.getAccounts';
6 const COLUMNS = [
7 { label: 'Account Name', fieldName: NAME_FIELD.fieldApiName, type: 'text' },
8 { label: 'Annual Revenue', fieldName: REVENUE_FIELD.fieldApiName, type: 'currency' },
9 { label: 'Industry', fieldName: INDUSTRY_FIELD.fieldApiName, type: 'text' }
10 ];
11 export default class AccountList extends LightningElement {
12 columns = COLUMNS;
13 @wire(getAccounts)
14 accounts;
15 }
四、Private和 Reactive的区别
Private 以及 Reactive,针对 Private,举一个不太恰当的比喻,在apex中可以声明变量为 private / public / global 类型,其中 private只能当前这个类当中引用,并且 apex page中无法引用,这里的 Private也有这层意思,区别是 Private类型变量可以在component中使用,但是他的后期的任何变化不会对component进行重新渲染,而且父页面也无法通过注入方式修改此类型变量;我们更多的要介绍的是 Reactive类型变量,此种变量的特点为当此变量改变以后,component便会重新渲染,在这个component中的所有的表达式都会重新计算。此种变量有两个类型: public / tracked(private). public 使用@api注解进行修饰。tracked使用@track注解进行修饰。这里需要注意的是,如果使用了@track 或者@api,必须要import track或者 import api在头部才能使用。
Tracked: Tracked类型也可以称为Private类型的Reactive,此种声明类型可以实现当变量改变以后,component进行reRender操作,此种类型的变量当其他的component引用以后,不可以通过attribute方式进行注入值,;此种类型头部声明需要引用:
import { LightningElement, track} from 'lwc';
Public:Public类型和Track类型区别为当其他的component进行引用时,可以通过attribute进行注入值。此种类型声明时头部需要引用:
import { LightningElement, api} from 'lwc';
看到上面这几种类型的介绍,我们可能会有一个疑问,声明成reactive是不是比private更好更方便?其实在变量声明时我们一定要千万的注意考虑好变量的作用域,变量类型。reactive类型当改变以后整个component都会reRender,所有template中包含的表达式都会被重新计算,使用不当可能会造成不准确或者不必要的性能影响,所以声明以前要考虑清楚变量用途。下面的Demo用来深化一下Tracked以及Public的用法。我们想要知道LWC封装了哪些component,我们可以访问:https://developer.salesforce.com/docs/component-library/overview/components进行查看。
既然reActive类型变量这么神奇,是否有什么相关的limitation呢?答案是有的。针对reActive类型变量只支持三种类型:
- Primitive values
- Plain objects created with
{…}
- Arrays created with
[]
只有这三种类型允许reActive,其他的类型即使声明了,也没法做到改变以后重新渲染component,并且会在console log里面提示你当前类型不支持track。