My child component does not re-render when parent data is changed in LWC

apexjavascriptlightning-web-componentslwc-wire-adapterparent-to-child

So I have situation where my Parent gets info from Child Component 1 and passes that to Child Component 2. Getting from Child Component 1 to Parent is okay as per console.log(), but my Child Component 2 does not re-render after the value is changed on Parent. Furthermore, my Child component 2 only renders correctly if I use @track, if I put @api it doesnt "call" @wire and I have an empty datable.

Here is my Parent html:

<template>
    <lightning-card>
        <c-search-by-network-or-country onsearchcountryornetwork={searchByNetworkOrCountryHandler}></c-search-by-network-or-country>
    </lightning-card>
    <lightning-card class="slds-m-top_medium">
        <c-display-networks country-text-search={countryFromSearch} network-text-search={networkFromSearch}></c-display-networks>
    </lightning-card>
</template>

Parent js:

import { LightningElement,api,track } from 'lwc';

export default class ParentComponent extends LightningElement {
    @api countryFromSearch;
    @api networkFromSearch;

    searchByNetworkOrCountryHandler(event){
        this.networkFromSearch = event.detail.NetworkText;
        this.countryFromSearch = event.detail.CountryText;
        console.log('searchedNetwork' + this.networkFromSearch);
    }
}

Child Component 1 js:

import { LightningElement,api } from 'lwc';

export default class SearchByNetworkOrCountry extends LightningElement {
    @api countryText;
    @api networkText;

    countryChangeHandler(event){
        this.countryText = event.target.value;
    }

    networkChangeHandler(event){
        this.networkText = event.target.value;
    }

    searchClickHandler(){
        console.log('called');
        const newEvent=new CustomEvent('searchcountryornetwork',{
            detail:{
                NetworkText:this.networkText,
                CountryText:this.countryText
            }
        });
        console.log('event' + newEvent);
        this.dispatchEvent(newEvent);
    }
}

Child Component 2 js:

export default class DisplayNetworks extends LightningElement {

  @track networkTextSearch='';
  @track countryTextSearch='';
  columns = columns;

  @wire(getJsonData,{insertCountryText:'$countryTextSearch',insertNetworkText:'$networkTextSearch'})
  parsedDataFromApex;

  constructor(){
    super();
    console.log('networkTextSearch' + this.networkTextSearch);
  }

}

My Apex class:

@AuraEnabled(cacheable=true)
public static List<JsonParserController> getJsonData(String insertCountryText,String insertNetworkText) {

    StaticResource jsonData = [SELECT Body FROM StaticResource WHERE Name = 'jsonDataNetworks'];

    String jsonString = jsonData.Body.toString();
    List<JsonParserController> parsedData = (List<JsonParserController>) System.JSON.deserialize(jsonString, List<JsonParserController>.class); 

    if (!String.isEmpty(insertCountryText) && !String.isEmpty(insertNetworkText)) {
        parsedData = filterByCountryAndNetwork(parsedData, insertCountryText, insertNetworkText);
    }
    else if (!String.isEmpty(insertCountryText)) {
        parsedData = filterByCountry(parsedData, insertCountryText);
    }
    else if (!String.isEmpty(insertNetworkText)) {
        parsedData = filterByNetwork(parsedData, insertNetworkText);
    }

    System.debug('now called' + parsedData);
    return parsedData;
}

Best Answer

@api properties are read-only in a component, and @track properties are not publicly accessible. Unlike Aura, data bindings are only one way, from parent to child.


import { LightningElement } from 'lwc';

export default class ParentComponent extends LightningElement {
    countryFromSearch;
    networkFromSearch;

    searchByNetworkOrCountryHandler(event){
        this.networkFromSearch = event.detail.NetworkText;
        this.countryFromSearch = event.detail.CountryText;
    }
}
import { LightningElement } from 'lwc';

export default class SearchByNetworkOrCountry extends LightningElement {
    countryText;
    networkText;

    countryChangeHandler(event){
        this.countryText = event.target.value;
    }

    networkChangeHandler(event){
        this.networkText = event.target.value;
    }

    searchClickHandler(){
        const newEvent=new CustomEvent('searchcountryornetwork',{
            detail:{
                NetworkText:this.networkText,
                CountryText:this.countryText
            }
        });
        this.dispatchEvent(newEvent);
    }
}
import { LightningElement, api, wire } from 'lwc';

export default class DisplayNetworks extends LightningElement {
  @api networkTextSearch;
  @api countryTextSearch;
  columns = columns;

  @wire(getJsonData,{insertCountryText:'$countryTextSearch',insertNetworkText:'$networkTextSearch'})
  parsedDataFromApex;
}
Related Topic