A fast Lightning Web Component feels more responsive and scales better. These performance tips focus on caching, lazy loading, and optimizing render cycles.
Mark Apex methods with @AuraEnabled(cacheable=true) so the framework can cache results.
@AuraEnabled(cacheable=true)
public static List getAccounts() {
return [SELECT Id, Name, Industry FROM Account LIMIT 100];
}
Only load expensive data when users need it, such as in tabs or expandable sections.
// example.js
import { LightningElement, track } from 'lwc';
import getLargeData from '@salesforce/apex/DataController.getLargeData';
export default class Example extends LightningElement {
@track data;
@track loaded = false;
async handleShowDetails() {
if (!this.loaded) {
this.data = await getLargeData();
this.loaded = true;
}
}
}
import { LightningElement } from 'lwc';
import { loadScript, loadStyle } from 'lightning/platformResourceLoader';
import chartJs from '@salesforce/resourceUrl/chartJs';
export default class ChartComponent extends LightningElement {
renderedCallback() {
if (this.chartInitialized) {
return;
}
this.chartInitialized = true;
Promise.all([
loadScript(this, chartJs + '/chart.min.js'),
loadStyle(this, chartJs + '/chart.css')
]).then(() => {
this.initializeChart();
});
}
}
Avoid changing properties repeatedly in quick succession and prefer getters for computed values.
get formattedName() {
return `${this.firstName} ${this.lastName}`;
}
setFirstName(value) {
this.firstName = value;
}
setLastName(value) {
this.lastName = value;
}
With modern LWC, only objects and arrays need @track. Simple fields are reactive by default.
// Prefer this
myCount = 0;
// Use @track only when updating nested properties
@track account = { name: '', phone: '' };
Query the DOM once instead of repeatedly inside loops.
renderedCallback() {
if (this.initialized) {
return;
}
this.initialized = true;
const elements = this.template.querySelectorAll('.item');
elements.forEach(el => {
el.classList.add('loaded');
});
}
Prevent too many updates by debouncing search fields and input events.
handleSearchChange(event) {
window.clearTimeout(this.searchTimeout);
this.searchTimeout = window.setTimeout(() => {
this.searchTerm = event.target.value;
this.performSearch();
}, 300);
}
Render only the UI elements needed at a given moment.
<template>
<template if:true={showDetails}>
<c-detail-panel data={detailData}></c-detail-panel>
</template>
</template>
@AuraEnabled(cacheable=true) for cached wire calls