3

Greetings StackExchange Friends!

I have an odd situation. I have this same design pattern on the Contact Object, and I'm attempting to replicate it on the Opportunity Object.

High Level:

c-parent-component: get's the record data and the user data.

c-child-alert-component: will receive data and determine if it should dispatch an alert.

*note: the child-alert-component is not currently being called in the parent-component's html, so it should not be impacting the rerun of this code yet.

Problem:

The parent component uses @wire and getRecord. When the Opportunity loads, the wire method fires twice. I'm not sure why it does, but it's causing my array to get duplicate values and could create unnecessary alerts.

Solution:

None yet. Tried removing @track on my array, but it had little effect. I believe that it might be related to the fact that I'm pulling in the values from a parent record, rather than from the Opportunity directly.

JS : Parent Component (HTML is just <template></template>)

import { LightningElement, api, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import {formatPhoneBare} from 'c/lwcFunctions'

//import methods
import getCurrentUser from '@salesforce/apex/LWC_ContactController.getCurrentUser';

//import fields
import USER_ID from '@salesforce/user/Id';
import PRIMARY_PHONE from '@salesforce/schema/Opportunity.Customer_Contact__r.Customer_Primary_Phone__c';
import PHONE_NUMBER_2 from '@salesforce/schema/Opportunity.Customer_Contact__r.Phone_2__c';
import PHONE_NUMBER_3 from '@salesforce/schema/Opportunity.Customer_Contact__r.Phone_3__c';

const fields = [PRIMARY_PHONE, PHONE_NUMBER_2, PHONE_NUMBER_3];

export default class OppCustomerPhoneData extends LightningElement {
    /* This component tree is used to alert agents if the customer contact on their opp needs an alternate phone added.
     * Structure:
     * Parent Component: OppCustomerPhoneData
     * * Child Component: OppContactPhoneAlert
    */

    @api objectApiName;
    @api recordId;

    // @track curPhoneNumber;
    // @track phone2;
    // @track phone3;
    phoneList = [];
    userObj = {
        ctmUserId: '',
        permission: ''
    }

    // test = this.isOpportunity(this.objectApiName);
    @wire(getRecord, {recordId: '$recordId', fields: fields})
    oppRecord({data,error}){
        if(data){
            console.log('OPP: Data Detected'); // The code block in the 'data' conditional is running 2x...not sure why?
            console.log(data)
            let curPhoneNumber = formatPhoneBare(getFieldValue(data,PRIMARY_PHONE));
            let phone2=formatPhoneBare(getFieldValue(data, PHONE_NUMBER_2));
            let phone3 = formatPhoneBare(getFieldValue(data, PHONE_NUMBER_3))
            // console.log(curPhoneNumber);
            // console.log(phone2);
            // console.log(phone3);


            if (curPhoneNumber) {
                this.phoneList.push(curPhoneNumber);
            }

            if (phone2) {
                this.phoneList.push(phone2);
            }

            if (phone3) {
                this.phoneList.push(this.phone3);
            }


        }else if (error) {
            console.log('Errors Detected');
            console.log(JSON.stringify(error));

        }

    }

    @wire(getCurrentUser, {userId: USER_ID})
    curUser({data, error}){
        if (data) {
            console.log('USER DATA');
            console.log(data);

            this.userObj.ctmUserId = data.Custom_Id__c;


        } else if(error){
            console.log('USER Data Not Found');

        }

    }
4
  • First point: there's wire or imperative, but no such thing as an "imperative wire". I think you mean a wire using dynamic, reactive variables. Second point: a wire fires when its parameters (which can be dynamic reactive variables) all have non-undefined values and, for reactive variables, when those variables change. You should also find that it is called with a {data: undefined, error: undefined} value during component initialization. However, unless the recordId value is changing during the component/page initialization, I am not sure how you would get called with data twice.
    – Phil W
    Jun 24, 2020 at 17:32
  • 1
    Since @wire methods use (Cacheable=true) I wonder if the behavior is the same as the one described here where the callback is being fired twice (once with cached data and once with fresh data). As a workaround, couldn't you clear this.phoneList every time you get data?
    – adriancg
    Jun 24, 2020 at 17:49
  • Thanks for the clarification on imperative. Sorry for the confusion, will update the post. I'm not sure why it would be changing either, since the recordId is not changing. The only thing that I can figure is that something else is running on the opp that may be changing is causing a re-render?
    – thinker
    Jun 24, 2020 at 17:49
  • It would appear that when new data is available, it will fire the function. According to the documentation: > The function is invoked whenever a value is available, which can be before or after the component is connected or rendered.
    – thinker
    Jun 24, 2020 at 17:53

1 Answer 1

3

Assuming this component lives on an Opportunity record, this is perfectly reasonable behavior. The record is already loaded once, so the cached version is returned, then LDS (Lightning Data Service) checks for an updated value, and then the wire method gets called again. Your code must be able to determine if a given value is already in the array and not add it again, but instead update the existing entry.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .