Detailed breakdown of Salesforce LWC concepts with examples :


1. LWC Architecture

Component-Based Architecture

  • What: LWC uses web standards (Custom Elements, Shadow DOM) to create reusable components.
  • Example:
  <!-- childComponent.html -->
  <template>
    <div class="child">Child Component: {message}</div>
  </template>
  // childComponent.js
  import { LightningElement, api } from 'lwc';
  export default class ChildComponent extends LightningElement {
    @api message = 'Hello from child!';
  }

Lifecycle Hooks

  • Order:
  1. constructor(): Initialize state (avoid touching DOM).
  2. connectedCallback(): Component inserted into DOM. Fetch data here.
  3. render(): Render the template (rarely overridden).
  4. renderedCallback(): After rendering. Use for DOM manipulation.
  5. disconnectedCallback(): Cleanup (e.g., remove event listeners).
  • Example:
  import { LightningElement } from 'lwc';
  export default class LifecycleDemo extends LightningElement {
    constructor() {
      super();
      console.log('Constructor called');
    }
    connectedCallback() {
      console.log('Component connected to DOM');
    }
    renderedCallback() {
      console.log('Component rendered');
    }
  }

2. Data Binding & Decorators

@api (Public Property/Method)

  • Purpose: Expose properties/methods to parent components.
  • Example:
  // child.js
  @api itemId;
  @api handleClick() { /* logic */ }
  <!-- parent.html -->
  <c-child item-id="123" onbuttonclick={handleClick}></c-child>

@track (Reactive Properties)

  • Purpose: Track changes to object/array properties (primitives are reactive by default).
  • Example:
  @track user = { name: 'John', age: 30 };
  updateUser() {
    this.user.name = 'Jane'; // Triggers re-render
  }

@wire (Reactive Data Fetch)

  • Purpose: Fetch data from Apex or Lightning Data Service (LDS).
  • Example:
  import { getRecord } from 'lightning/uiRecordApi';
  // Wire to LDS
  @wire(getRecord, { recordId: '$recordId', fields: ['Account.Name'] })
  account;
  // Wire to Apex (Apex method must be cacheable)
  import getContacts from '@salesforce/apex/ContactController.getContacts';

  @wire(getContacts, { accountId: '$recordId' })
  wiredContacts({ error, data }) {
    if (data) {
 /* handle data */ 
      }
  }

3. Component Communication

Parent → Child

  • Use @api to pass data or call methods.
  • Example:
  &lt;!-- parent.html -->
  &lt;c-child message="Hello Parent!">&lt;/c-child>

Child → Parent (Custom Events)

  • Dispatch events from child, handle in parent.
  • Example:
  // child.js
  handleClick() {
    this.dispatchEvent(new CustomEvent('notify', { detail: 'Data from child' }));
  }
  <!-- parent.html -->
  <c-child onnotify={handleNotification}></c-child>
  // parent.js
  handleNotification(event) {
    console.log(event.detail); // "Data from child"
  }

Cross-Component (Lightning Message Service)

  • Example:
  // Component A (publish)
  import { publish, MessageContext } from 'lightning/messageService';
  export default class Publisher extends LightningElement {
    @wire(MessageContext) messageContext;
    handlePublish() {
      const payload = { recordId: '001xx...' };
      publish(this.messageContext, CHANNEL, payload);
    }
  }
  // Component B (subscribe)
  import { subscribe, MessageContext } from 'lightning/messageService';
  export default class Subscriber extends LightningElement {
    @wire(MessageContext) messageContext;
    subscription;
    connectedCallback() {
      this.subscription = subscribe(
        this.messageContext,
        CHANNEL,
        (payload) => { /* handle payload */ }
      );
    }
  }

4. Apex Integration

Reactive (@wire) vs. Imperative Calls

  • Reactive (cached data):
  @wire(getContacts, { accountId: '$recordId' }) contacts;
  • Imperative (for DML operations):
  import updateContact from '@salesforce/apex/ContactController.updateContact';
  handleSave() {
    updateContact({ contact: this.contact })
      .then(() => { /* success */ })
      .catch(error => { /* handle error */ });
  }

Apex Method Structure:

  // ContactController.cls
  @AuraEnabled(cacheable=true)
  public static List<Contact> getContacts(String accountId) {
    return [SELECT Id, Name FROM Contact WHERE AccountId = :accountId];
  }

5. Lightning Data Service (LDS)

getRecord and updateRecord

  • Example:
  import { getRecord, updateRecord } from 'lightning/uiRecordApi';
  // Fetch data
  @wire(getRecord, { recordId: '$recordId', fields: FIELDS }) account;
  // Update data
  async handleSave() {
    const fields = { ... };
    await updateRecord({ fields });
  }

6. Security

Lightning Web Security (LWS)

  • Purpose: Replace Locker Service to enforce security boundaries.
  • Example: Sanitize HTML to prevent XSS:
  import { sanitizeHtml } from 'lightning/utilsPrivate';
  const unsafeHtml = '&lt;script>alert("XSS")&lt;/script>';
  const safeHtml = sanitizeHtml(unsafeHtml); // Sanitizes the HTML

7. Testing (Jest)

Test a Component:

  // myComponent.test.js
  import { createElement } from 'lwc';
  import MyComponent from 'c/myComponent';

  test('displays greeting', () => {
    const element = createElement('c-my-component', { is: MyComponent });
    document.body.appendChild(element);
    const div = element.shadowRoot.querySelector('div');
    expect(div.textContent).toBe('Hello, World!');
  });

8. Debugging & Deployment

Debugging:

  • Use Chrome DevTools (Components and Console tabs).
  • console.log(this.property) to track reactive values.

Deployment:

  • Salesforce CLI Commands:
  sfdx force:source:deploy -p ./force-app/main/default/lwc
  sfdx force:org:open

Example Scenario: Search with Debounce

<!-- searchComponent.html -->
<template>
  <lightning-input
    type="search"
    onchange={handleSearch}
    label="Search"
  ></lightning-input>
</template>
// searchComponent.js
import { LightningElement } from 'lwc';
export default class SearchComponent extends LightningElement {
  timer;
  handleSearch(event) {
    clearTimeout(this.timer);
    const searchTerm = event.target.value;
    // Debounce to avoid excessive Apex calls
    this.timer = setTimeout(() => {
      this.dispatchEvent(new CustomEvent('search', { detail: searchTerm }));
    }, 300);
  }
}

Key Takeaways

  • Modularity: Break down components for reusability.
  • Reactiveness: Use decorators (@track, @wire) wisely.
  • Events: Master parent-child and cross-component communication.
  • Security: Sanitize inputs and follow LWS guidelines.

This site uses cookies to offer you a better browsing experience. By browsing this website, you agree to our use of cookies.