LWC Development Best Practices
This story is based on what I learned from building applications so far using lightning web components. I am writing this on 27th Dec 2020. As always, tech keeps changing and evolving for the better. So, what I write today might have changed or could be different 6 months down the line.
Yes— change is inevitable!
Instantiate the component only when necessary
Use conditional rendering to take out components from DOM if not needed. You can do this in 3 ways:
- Use conditional visibility in app builder.
- Use if: true or if: false in the HTML code.
- Use CSS to show and hide. You can use a combination of javascript to dynamically apply slds-show or shlds-hide classes to html elements. Use this method only if necessary. This is because CSS hide won’t take the component from the shadow, and keeps the state (maybe a plus based on your needs?)
Leverage base components
The first place to look for is to see if Salesforce offers any base component. If there is none, only then build a custom component. Building a custom styling using external stylesheets is not recommended and it’s expected that developers are familiar with SLDS that salesforce has built out and leverage it for styling. This keeps the experience very much consistent.
Lightning Icons
Instead of spending time to design and build your own icons, you can leverage the vast number of icons from the SLDS icon library. Try to re-use the icons that your organization use. For example: using the Opportunity icons for a custom feature might confuse the users.
That said, you are free to use icons from other sources.
Fetching Data — Lightning Data Service
Leverage Lightning Data Service to the maximum to fetch data from the server. The framework will do all the heavy lifting for you including security and caching. There are ways of using LDS:
- Components —
lightning-record-edit-form
,lightning-record-form
, andlightning-record-view-form
- Wire adapters and functions in the
lightning/ui*Api
modules
Fetching Data — Apex
In those scenarios where you need to do some computation at the server, you will have to depend on writing an apex class that sends the data to the LWC component. The first choice should to cache these apex AuraEnabled
methods using cacheable=true
.
If you have to do any DML operation, then ensure that the cacheable is set to false.
The first choice of calling apex from the component should be using a wire service. It’s recommended to use wire service for all your server calls. Unless it’s not possible to use wire call, make an imperetive apex call.
Events/Communication
There are four ways to communicate between other compnents in the application.
- Parent to Child: Use @api attributes on the variables in the child component and directly pass the values from the parent when instantiating. Ex:
<c-file-list files={fileData}></c-file-list>
- Child to Parent: Use “composed” events. Fire an event (default is “composed”), from the child component and handle that on the parent component. Ex:
this.dispatchEvent(new CustomEvent('closefullscreen'));
<c-file-list files={fileData} onclosefullscreen={handleCloseFullScreen}></c-file-list> - Fire up events through the shadow: If you want you event to be consumed by other components in the heirarchy — grand parent for instance, you can fire an event as a bubble event. Just set the attribute bubble:true. Ex:
this.dispatchEvent(new CustomEvent('closefullscreen'),{ bubbles: true });
- Lightning Message Service (LMS) — Use this to communcate between sibling components in the application. From a source component, fire an LMS event which can be consumed (subscribed) by other components. By offloading the data fetching job to just one component, we can improve the performance of the application. Sample code from Salesforce doc:
import { LightningElement, wire } from 'lwc';
import { publish, MessageContext } from 'lightning/messageService';
import SAMPLEMC from '@salesforce/messageChannel/SampleMessageChannel__c';
export default class PublisherComponent extends LightningElement {
@wire(MessageContext)
messageContext;
handleClick() {
const message = {
recordId: '001xx000003NGSFAA4',
recordData: {accountName: 'Burlington Textiles Corp of America'}
};
publish(this.messageContext, SAMPLEMC, message);
}
}
Of course, there are more to this than these above, however, I believe the above summary will help you to get started. Debugging is another area where you could rely on Chrome dev tools heavily. Interesting resource on Chrome Dev tool can be found here.
Also, check the performance of your page/app using the Performance Analysis to see which resource consumes most resources.
Let me know your thoughts and comments as well. Thanks!