Lightning Web Components – Events & Communication Questions

Effective communication between components is crucial for building cohesive and maintainable LWC applications. These questions cover the different event communication patterns, custom event handling, parent-child communication, Lightning Message Service, and best practices for implementing robust component interactions. Understanding these concepts will help you build well-structured and scalable LWC solutions.

LWC Events & Communication - Q&A

  1. Q1. What are the different event communication patterns in LWC?
    Ans: Four key patterns: - Parent-to-Child: Using public methods/properties (@api) - Child-to-Parent: Custom events with dispatchEvent() - Sibling Components: Parent as mediator or pub/sub - Unrelated Components: Lightning Message Service or state management
  2. Q2. How do you dispatch and handle custom events?
    Ans: Event flow:
    // Child component (dispatch)
    this.dispatchEvent(new CustomEvent('notify', {
      detail: { message: 'Hello' },
      bubbles: true,    // Propagates up
      composed: false   // Doesn't cross shadow boundary
    }));
    
    // Parent component (handle)
    
    
    handleNotification(event) {
      console.log(event.detail.message);
    }
  3. Q3. What's the difference between bubbles and composed in events?
    Ans: Event propagation: - bubbles=true: Event bubbles up DOM hierarchy - composed=true: Event crosses shadow DOM boundaries - Defaults: bubbles=false, composed=false - Use composed carefully (security implications)
  4. Q4. How do you expose child methods to parent components?
    Ans: Using @api methods:
    // Child component
    @api
    refreshData() {
      return fetchData();
    }
    
    // Parent component
    
    
    handleCreate(event) {
      this.childRef = event.detail;
      this.childRef.refreshData().then(...);
    }
  5. Q5. How do you implement two-way data binding?
    Ans: Pattern combining @api and events:
    // Child component
    @api value;
    
    handleChange(event) {
      this.dispatchEvent(new CustomEvent('change', {
        detail: { value: event.target.value }
      }));
    }
    
    // Parent component
    
    
    handleChange(event) {
      this.boundValue = event.detail.value;
    }
  6. Q6. What is Lightning Message Service and when to use it?
    Ans: Cross-component messaging: - Use when components aren't in same hierarchy - Implementation:
    // messageChannel.js
    import { LightningElement, wire } from 'lwc';
    import { publish, MessageContext } from 'lightning/messageService';
    import SAMPLEMC from '@salesforce/messageChannel/SampleMessageChannel__c';
    
    export default class Publisher extends LightningElement {
      @wire(MessageContext) messageContext;
    
      handlePublish() {
        const payload = { recordId: '123' };
        publish(this.messageContext, SAMPLEMC, payload);
      }
    }
    
    // Subscriber component
    @wire(MessageContext) messageContext;
    subscription;
    
    connectedCallback() {
      this.subscription = subscribe(
        this.messageContext,
        SAMPLEMC,
        (message) => { console.log(message.recordId); }
      );
    }
  7. Q7. How do you communicate between LWC and Aura components?
    Ans: Interoperability methods: - Use aura:method in wrapper Aura component - Application events (Aura) + LMS (LWC) - Custom events with composed:true Example Aura wrapper:
    
      
    
  8. Q8. What are the best practices for event naming?
    Ans: Naming conventions: - Use lowercase with hyphens (e.g., 'itemselected') - Prefix with domain (e.g., 'cartupdated') - Avoid generic names ('change', 'click') - Document event signatures - Example good name: 'productquantitychanged'
  9. Q9. How do you test event dispatching?
    Ans: Testing strategy:
    // Test event dispatch
    const element = createElement('c-publisher', { is: Publisher });
    document.body.appendChild(element);
    
    // Simulate user action
    element.shadowRoot.querySelector('button').click();
    
    // Verify event
    return Promise.resolve().then(() => {
      const dispatchedEvents = element.getDispatchedEvents();
      assert(dispatchedEvents.length === 1);
    });
  10. Q10. How do you prevent memory leaks with events?
    Ans: Cleanup patterns: - Remove event listeners in disconnectedCallback:
    connectedCallback() {
      this.addEventListener('keydown', this.handleKey);
    }
    
    disconnectedCallback() {
      this.removeEventListener('keydown', this.handleKey);
    }
    - Unsubscribe LMS subscriptions - Clear timeouts/intervals
  11. Q11. How do you implement a pub/sub pattern in LWC?
    Ans: Custom event bus:
    // eventBus.js
    const callbacks = {};
    
    export const register = (eventName, callback) => {
      if (!callbacks[eventName]) callbacks[eventName] = new Set();
      callbacks[eventName].add(callback);
    };
    
    export const unregister = (eventName, callback) => {
      callbacks[eventName]?.delete(callback);
    };
    
    export const dispatch = (eventName, payload) => {
      callbacks[eventName]?.forEach(cb => cb(payload));
    };
    
    // Usage in components
    import { register, unregister } from 'c/eventBus';
    
    connectedCallback() {
      register('dataUpdate', this.handleUpdate.bind(this));
    }
    
    disconnectedCallback() {
      unregister('dataUpdate', this.handleUpdate.bind(this));
    }
  12. Q12. How do you handle errors in event communication?
    Ans: Error handling patterns: - Include error details in event payloads - Use status flags in events:
    this.dispatchEvent(new CustomEvent('load', {
      detail: {
        data: null,
        error: 'Failed to load',
        status: 'error'
      }
    }));
    - Implement global error event listeners
  13. Q13. How do you communicate between LWCs in different DOM branches?
    Ans: Solutions: 1. Lightning Message Service (preferred) 2. Parent mediator (common ancestor) 3. Custom event bus (singleton service) 4. Browser storage (localStorage events)
  14. Q14. How do you implement drag-and-drop events?
    Ans: Native event handling:
    handleDragStart(event) { event.dataTransfer.setData('text/plain', this.itemId); } handleDrop(event) { const itemId = event.dataTransfer.getData('text/plain'); // Handle drop logic }
  15. Q15. How do you throttle event handlers for performance?
    Ans: Rate-limiting pattern:
    handleScroll = (function() {
      let lastCall = 0;
      const delay = 200; // ms
      
      return function(event) {
        const now = new Date().getTime();
        if (now - lastCall < delay) return;
        lastCall = now;
        // Actual scroll handling
      };
    })();
  16. Q16. How do you test LMS subscriptions?
    Ans: Testing approach:
    // Create test message context
    const messageContext = createMessageContext();
    
    // Create and connect component
    const element = createElement('c-subscriber', { is: Subscriber });
    element.messageContext = messageContext;
    document.body.appendChild(element);
    
    // Publish test message
    publish(messageContext, SAMPLEMC, { recordId: '123' });
    
    // Verify handling
    return Promise.resolve().then(() => {
      const consoleSpy = spyOn(console, 'log');
      expect(consoleSpy).toHaveBeenCalledWith('123');
    });
  17. Q17. How do you document event contracts between components?
    Ans: Documentation practices: - JSDoc for @api methods/events - Markdown docs in component folders - Example event documentation:
    /**
     * Fires when data loading completes
     * @event DataLoader#load
     * @type {CustomEvent}
     * @property {Object} detail - Event payload
     * @property {Array} detail.data - Loaded records
     * @property {string} detail.status - "success" or "error"
     */

Back to LWC Home