19 - @api / parent-child and child -parent communication / @track

 In Lightning Web Components (LWC), the @api decorator primarily allows parent components to access and modify properties or call methods defined in the child component. However, it does not work in the reverse direction – a child component cannot directly access the parent’s properties or methods using @api.

Here's a summary of how @api works:

  1. Child Properties Accessible by Parent:

    • When you use @api on a property or method in the child component, it makes that property or method "public" so the parent component can access and set it.
    • For example, a child component might expose a property with @api, which allows the parent to pass values to it.
    javascript
    // childComponent.js import { LightningElement, api } from 'lwc'; export default class ChildComponent extends LightningElement { @api childProperty; // Exposed to parent @api childMethod() { // Exposed method that parent can call console.log('Child method called by parent'); } }
  2. Parent Properties are Not Directly Accessible by Child:

    • The child component cannot directly access properties or methods of the parent component. LWC maintains a unidirectional data flow from parent to child for properties.
    • If a child component needs to "send" data to the parent, it typically does so using events (as we discussed with dispatchEvent), rather than directly accessing parent properties.
  3. Parent-to-Child Communication:

    • The parent can set properties on the child component (thanks to @api) and can call public methods in the child using @api.
    • This means that @api only enables communication from the parent to the child, allowing the parent to set data or trigger behavior in the child.
  4. Child-to-Parent Communication (via Events):

    • For a child to communicate back to the parent, events are used (e.g., dispatchEvent with a CustomEvent).
    • This event-based communication allows the child to send data up to the parent without directly accessing the parent's properties. 

Example Summary

  1. Parent can set child properties and call child methods using @api.

    • This enables the parent to control certain aspects of the child component.
  2. Child cannot access parent properties or methods directly.

    • To send data to the parent, the child dispatches an event.
------------------------CODE EXAMPLE -------------

METHOD 1 : We'll create two components: a parent component (ParentComponent) and a child component (ChildComponent). The parent will pass data to the child, and the child will communicate back to the parent using a custom event.

Step 1: Create the Child Component

  1. Child Component JavaScript: childComponent.js

    Define a property with @api to receive data from the parent, and create a method to dispatch an event back to the parent.

    javascript
    // childComponent.js import { LightningElement, api } from 'lwc'; export default class ChildComponent extends LightningElement { @api messageFromParent; // Data received from the parent // Method to handle button click and send data back to parent handleButtonClick() { const event = new CustomEvent('sendmessage', { detail: 'Hello Parent, from Child!' }); this.dispatchEvent(event); // Dispatch event to send data to the parent } }
  2. Child Component HTML: childComponent.html

    Use the messageFromParent variable to display the message received from the parent and create a button that, when clicked, sends a message back.

    html
    <!-- childComponent.html --> <template> <p>Message from Parent: {messageFromParent}</p> <button onclick={handleButtonClick}>Send Message to Parent</button> </template>

Step 2: Create the Parent Component

  1. Parent Component JavaScript: parentComponent.js

    In the parent component, define a variable to store the message to be sent to the child. Also, define a handler function for the event coming from the child.

    javascript
    // parentComponent.js import { LightningElement } from 'lwc'; export default class ParentComponent extends LightningElement { parentMessage = 'Hello Child, from Parent!'; // Message to send to the child receivedMessage = ''; // To store the message received from the child // Method to handle the event from the child handleChildMessage(event) { this.receivedMessage = event.detail; // Get message from child console.log('Message from Child:', this.receivedMessage); } }
  2. Parent Component HTML: parentComponent.html

    Use the child component and pass data to it using message-from-parent. Set up an event listener onmessage to handle the custom event from the child.

    html
    <!-- parentComponent.html --> <template> <h1>Parent Component</h1> <p>Received Message: {receivedMessage}</p> <!-- Pass message to child and handle event from child --> <c-child-component message-from-parent={parentMessage} onsendmessage={handleChildMessage}> </c-child-component> </template>

Explanation

  1. Data Flow from Parent to Child:

    • The parent passes a message to the child component using message-from-parent.
    • In the child component, this message is displayed using {messageFromParent}.
  2. Event from Child to Parent:

    • When the child component's button is clicked, it dispatches a custom event (sendmessage) with a message for the parent.
    • The parent component listens to this event using onsendmessage and handles it with handleChildMessage, which updates receivedMessage with the message from the child.
METHOD 2 : CONSTRUCTOR METHOD FOR CHILD-TO-PARENT COMMUNICATION

In Parent js -->
constructor(){
        super();
        this.template.addEventListener('tileclick', this.onTileSelectHandler.bind(this));
    }

In Child js -->
tileClickHandler(){
        const tileClicked = new CustomEvent('tileclick', {detail : this.meetingRoomInfo, bubbles :true});

        this.dispatchEvent(tileClicked);
    }


------------------

In Lightning Web Components (LWC), the @track decorator was used to make a property reactive, so changes to that property would update the component's UI automatically. However, starting in Spring '20, @track became mostly obsolete due to the introduction of reactive proxies, meaning that any change to a field within an object or an array will automatically trigger UI updates without @track. Now, you only need @track in specific scenarios:

  1. Nested Objects and Arrays: When you're working with deeply nested properties, like myObject.childProperty, you might need @track if the updates aren't being detected. But in most cases, LWC's reactivity should handle this without @track.

  2. Direct Field Reassignments: If you replace the entire object or array (e.g., this.myArray = newArray), the reactivity should work without @track.

Here’s a simple example of using @track:

javascript
import { LightningElement, track } from 'lwc'; export default class MyComponent extends LightningElement { @track myObject = { name: 'Salesforce', location: 'Cloud' }; handleChange() { // Updates the tracked property this.myObject.name = 'New Name'; } }

But nowadays, you typically won’t need @track if you're working with a regular assignment or mutation at the top level. For complex state management, you might still find @track useful in exceptional cases, but for most applications, standard reactivity should suffice.

Comments

Popular posts from this blog

API Names in Salesforce

18 - LWC - BEST PRACTICES - For accessing HTML elements and their values in JavaScript

6 - Object Relationships (Lookup and Master-Detail and Junction Objects)