8

Looking to socialize a new child-to-parent data communication mechanism my colleague has proposed that we use in our LWC project. His approach involves passing arrow function expressions from the parent component to the child, which are then called by the child when making updates.

In testing, this approach appears to perform 3-10x better than communicating with events, and is even slightly less verbose than the event-based approach that is normally recommended. Here's the rundown.

A parent component that communicates with events like this...

<template>
    <c-child name={name} onupdateevent={handleUpdateEvent}></c-child>
</template>
export default class Parent extends LightningElement {
    @track name = 'John Doe';

    // A STANDARD EVENT HANDLER
    handleUpdateEvent(e) { 
        this.name = e.detail;
    }
}

...instead passes an arrow function as an attribute to the child:

<template>
    <c-child name={name} update-function={updateFunction}></c-child>
</template>
export default class Parent extends LightningElement {
    @track name = 'John Doe';

    // ARROW FUNCTION TO PASS TO CHILD
    updateFunction = (update) => { 
        this.name = update;
    }
}

The child's template doesn't change at all:

<template>
    <lightning-input 
        type="text" 
        label="Participant Name"  
        value={name} 
        onchange={handleInputChange}
    ></lightning-input>
</template>

And in JS, instead of dispatching a custom event...

export default class Child extends LightningElement {
    @api name;

    handleInputChange(e) {
        this.dispatchEvent(new CustomEvent('updateevent', {detail: e.target.value}));
    }
}

... the child simply defines the function as a public reactive property, and calls it:

export default class Child extends LightningElement {
    @api name;
    @api updateFunction;

    handleInputChange(e) {
        this.updateFunction(e.target.value);
    }
}

This approach is made possible by a special trait of arrow functions where this always refers to the enclosing lexical scope -- in this case, the parent component.

My Playground Example includes a more complex example and a speed test button. Very interested in whether the experts here can find fault with this pattern, or if it could in fact provide a suitable (dare I say preferable?) approach to component communication.

  • Appreciate to share this approach – Santanu Boral Dec 12 '19 at 4:14
6

Firstly,
this is not documented. As a thumb-rule, salesforce always insists to use ONLY what is documented. So, this may some day be made invalid by salesforce the sameway they did Prevent Creation of Function Expressions in Dynamically Created Aura Components (Critical Update). Although passing function expressions in attributes (properties) of dynamically created components seemed normal, it seems it created memory leaks and they considered it anti pattern (The same way you are passing function expressions to javascript properties in child component). So, even what you are suggesting may become invalid someday according to LWC coding practices as its not documented.

Secondly,
this way of implementing communication is very very limited to strictly child-parent relationship.

Scenario-1: it works in this scenario

<c-parent>
    <c-child>

Scenario-2: if you want to use same child or parent in another flow, you will have to implement another relationship between parent/container and container/child

<c-parent>
    <c-container>
        <c-child>

Clearly, it will lead to much more complicated code compared to events.

Regarding performance difference, its negligible. You just pass data from 1 component to another and a user will never notice any kind of delay or fastness when you choose one over the other.

Conclusion: I would suggest events is the best way to implement communication for bottom up in hierarchy considering above 2 points.

|improve this answer|||||
  • These are very good points, particularly #1. That one alone may prove decisive for us. Thank you! – Matthew Souther Dec 12 '19 at 17:11
  • For what it's worth, a few counterpoints to #1 that I've become aware of... A) we haven't seen any evidence of a memory leak testing this approach so far, B) LWC is much more open than Aura, and the tendency has been not to interfere too much with JS capabilities, and C) the JavaScript Skills for Salesforce Developers module on Trailhead promotes arrow functions as something cool that devs should know, use, and love (which begs the question: for what use case, if not this one?) – Matthew Souther Dec 12 '19 at 19:04
6

I'd be surprised if they don't have this approach documented anywhere. It's pretty standard in other web frameworks, but works for a different kind of communication paradigm to events.

Events keep everything loosely coupled, and if you needed later on to support communications with a component outside of the hierarchy then you'd be good to go, but there are a lot of cases where you know it won't go beyond the child -> parent route and in that case this would work fine.

One thing I would say though is that it often pays to be consistent, so perhaps just using events everywhere is the better option regardless? You'd need a whole lot of messaging going on for the performance overhead to affect a real-world use case, but that's not to say there aren't cases where it'd be the better choice.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.