Реактивность в LWC

Всем привет!

Очень часто разработчики используют фреймворк VisualForce для фронтенд разработки на платформе Salesforce. Все мы любим и уважаем VisualForce, т.к. он довольно прост и неприхотлив. Большие компании все еще предпочитают его для разработки крупных приложений, но все же он не лишен недостатков. В ответ на действие пользователя приходится каждый раз генерировать новую страницу и отправлять ее пользователю, что не лучшим образом влияет на отзывчивость интерфейса и быстродействие сайта в целом. Фреймворк Lightning, в ядре которого лежит реактивность, позволит создавать быстрые и отзывчивые приложения, идеально подходящие для малых и средних проектов. Планируется серия статей про Lightning, в которых мы обсудим такие основополагающие темы как жизненный цикл компонента, взаимодействие фреймворка с апексом, императивность и многое другое, в этой же поговорим про такой немаловажный аспект фреймворка, как реактивность.

Реактивность - это система, лежащая в основе инфраструктуры веб-компонентов Lightning. Платформа отслеживает изменения значений полей и свойств (о которых поговорим дальше). Когда платформа замечает изменение, она реагирует и повторно оценивает все выражения, используемые в шаблоне.

Начиная с весны 2020 года, в Lightning все поля по умолчанию являются реактивными, что значит, если значение поля изменяется и поле используется в шаблоне, компонент повторно визуализируется и отображает новое значение.

Для наглядности рассмотрим следующий простой пример. Создадим простую форму для ввода текстового сообщения:

<template>
    <lightning-card title="Check reactivity" icon-name="custom:custom14">
        <div class="slds-m-around_medium">
            <lightning-input name="input" label="Enter text" onchange={handleChange}></lightning-input>
            <p class="slds-m-top_medium" style="display">
                Current field value : {inputText}
            </p>
        </div>
    </lightning-card>
</template>

Внутри java-script файла нашего компонента создадим поле inputText которое будет хранить в себе значение введенное с формы:

import { LightningElement } from 'lwc';
export default class TrackExample extends LightningElement {

    inputText = '';

    handleChange(event) {
        this.inputText = event.target.value;
    }
}

Метод handleChange получает значение, введенное в lightning input, и присваивает его полю inputText, а так как поле является по умолчанию реактивным и используется в template — мы можем наблюдать его динамическое изменение на UI.

Для обеспечения реактивности Lightning также может использовать такие аннотации как
(track, wire, api). Рассмотрим каждую из них подробней.

Нередко возникает ситуация, когда поле содержит в себе объект или массив, и для того, чтобы фреймворк отслеживал изменения свойств этого объекта, его необходимо декорировать как track, что даст возможность визуализировать поле каждый раз когда изменяется его свойство. Рассмотрим небольшой пример. Немного модифицируем наш компонент файл:

<template>
    <lightning-card title="Check reactivity" icon-name="custom:custom14">
        <div class="slds-m-around_medium">
             <lightning-input name="input" label="Enter text" onchange={handleChange}></lightning-input>
             <lightning-input name="inputNumber" label="Enter Number" onchange={handleChangeNumber}></lightning-input>
            <div>
                <p class="slds-m-top_medium" style="display">
                    Current field value : {inputText}
                </p>
                <p class="slds-m-top_medium">
                Check track annotation : {fullValue.inputNumber}
                </p>
            </div>
        </div>
    </lightning-card>
</template>
import { LightningElement,track } from 'lwc';
export default class TrackExample extends LightningElement {

    inputText = '';

    inputNumber = '';

    @track fullValue = {inputText: '', inputNumber: ''};

    handleChange(event) {
        this.inputText = event.target.value;
    }

    handleChangeNumber(event) {
        this.fullValue.inputNumber = event.target.value;
    }

}

Здесь fullValue является объектом, который содержит себе 2 поля (свойства), на разметке мы обращаемся к одному из его свойств. Без аннотации track компонент не будет повторно визуализировать inputNumber при его изменении, так как по умолчанию фреймворк не отслеживает изменения свойств объекта.

Аннотация api является уникальной для LWC, и также делает поле реактивным. Ее особенность в том, что поле становится публичным и значение в него можно установить из другого (родительского) компонента. Представим себе ситуацию, в которой мы имеем 2 компонента, один является родительским второй дочерним.

Родительский компонент:

<template>
    <lightning-card title="HelloExpressions" icon-name="custom:custom14">
        <div class="slds-m-around_medium">
            <lightning-input name="" label="Parent Component" onchange={handleChange}></lightning-input>
        </div>
        <c-child item-name={inputValue}></c-child>
    </lightning-card>
</template>
import { LightningElement } from 'lwc';
export default class TrackExample extends LightningElement {

    inputValue;

    handleChange(event) {
        this.inputValue = event.target.value;
    }
}

Дочерний компонент:

<template>
    <div class="view slds-m-around_medium">
        <p>
            Child Component: {itemName}
        </p>
    </div>
</template>
import { LightningElement, api } from 'lwc';
export default class TrackExample extends LightningElement {
    @api itemName = '';
}

В дочернем компоненте мы объявим поле itemName и декорируем его аннотацией api, после чего вызовем дочерний компонент в родительском:

<c-child item-name={inputValue}></c-child>

В атрибут item-name, объявленный в дочернем компоненте, предадим данные, введенные пользователем, и, как можно заметить дочерний компонент успешно отрисовывает пользовательский ввод. Это стало возможным благодаря аннотации api; без нее у родительского компонента не будет доступа к переменной объявленной в дочернем компоненте.

Третья аннотация wire позволяет обращаться к методам из апекса и на основе возвращенных значений строить бизнес логику. Более подробно о wire поговорим в следующей статье, но в рамках реактивности стоит упомянуть, что данная аннотация позволит постоянно получать актуальные данные из вашей salesforce организации , что отлично вписывается в реактивную архитектуру LWC.

Напоследок. Не стоит забывать, что для того, чтобы использовать любую из выше описанных аннотаций — ее необходимо импортировать из LWC следующим образом:

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

Исходя из выше перечисленного, мы можем убедится что реактивность в Lightning позволит нам создавать понастоящему отзывчивый приложения , которые будут динамично реагировать на действия пользователя, используя встроенную реактивность. В следующей статье рассмотрим взаимодействия компонента с апексом , а также императивный подход к получению данных из вашей органицации.

8 Likes