How to get an LWC component on a record page to refresh when that page is updated

ADDED

wire service getWorkingDays is dependent on record.id. So, this wire will invoke again only when record.id changes. But, although getRecord service is invoked every-time record is updated, its id never changes and so getWorkingDays is never getting invoked again.

You can use imperative apex call and use it inside getRecord function or you can try refreshApex inside getRecord


OLD ANSWER

getRecord from uiRecordApi is based on lightning data services and so it will be invoked automatically when the record is updated.

Sample JS code:

import { LightningElement, wire, api, track } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';

export default class Poc extends LightningElement {
    @api recordId;
    @track account;

    @wire(getRecord, { recordId: '$recordId', fields: [ 'Account.Name', 'Account.Phone' ] })
    getaccountRecord({ data, error }) {
        console.log('accountRecord => ', data, error);
        if (data) {
            this.account = data;
            this.processRelatedObjects();
        } else if (error) {
            console.error('ERROR => ', JSON.stringify(error)); // handle error properly
        }
    }

    processRelatedObjects() {
        console.log('processRelatedObjects for => ', JSON.stringify(this.account));
        // further processing like refreshApex or calling another wire service
    }
}

Proof:

enter image description here


Added based on comments:

Its working even for related list:

enter image description here


Given @salesforce-sas's answer (patiently built up iteratively with me) the following points should be noted:

My implementation's chaining of wired service calls was broken and here's why...

As a bit of background, when you set up a tracked property you have basically two choices:

  1. Have tracked changes trigger processing if the property itself changes by declaring it like:

    @track someProperty;

  2. Have tracked changes trigger processing if values of sub-properties change by declaring it like:

    @track someProperty = { knownSubProperty1: undefined, knownSubProperty2: undefined };

HOWEVER, if you use one of the properties from that tracked property as a dynamic parameter in a wired service call then it appears the wire is only invoked when the actual value of that property changes.

In my case the property value was not changing, after the first call, since it was effectively set to the record ID for the page, which (of course) doesn't change over the lifetime of the page.

The solution, for me, was to convert the wired call to my getWorkingDays Apex method into an imperative call and make this service uncached. This impacts the code shown in the question as follows. Firstly the handling of retrieving the record details becomes:

@wire(getRecord, {recordId: '$recordId', fields: [TOTAL_LENGTH_FIELD, CYCLE_LENGTH_FIELD]})
receiveRecord({error, data}) {
    if (error) {
        this.error = WorkSchedule.getErrorMessage(error);
    } else if (data) {
        // Populate the tracked record details. Note that the cycle length may be unspecified in which case
        // it is treated as being set to the same value as the length. The length must be specified
        this.record = {
            id: this.recordId,
            length: data.fields.namespace__Length__c.value,
            cycle: data.fields.namespace__CycleLength__c.value || data.fields.namespace__Length__c.value
        };

        // Refresh the view of the data
        this._refreshView();
    }
}

Next, the original wired call to get the details for presentation is converted to the new private _refreshView function:

/**
 * Fetches the working days related to the component's record. This only does anything when  the ID from the
 * fetched record data is set to ensure that the total and cycle lengths are already known before the data
 * is fetched.
 *
 * @private
 */
_refreshView() {
    if (this.record.id) {
        // Imperatively obtain the working days detail
        getWorkingDays({workScheduleId: this.record.id}).then(workingDaysByOffset => {
            if (workingDaysByOffset) {
                ... // Lots of processing to set up the visual presentation data
            } else {
                // Clear the visuals
                ...
            }
        }).catch(error => {
            this.error = WorkSchedule.getErrorMessage(error);
        });
    }
}

With this, when changes are made to the record, the getRecord wire is invoked and this in turn explicitly calls the _refreshView function. This then imperatively invokes the service to get the child objects to present visually in the component.

Note that I found that this did not resolve handling of updates to instances in the related list, rather than through my component, likely because these instances are not fetched, in the component, using getRecord but rather are returned by getWorkingDays. This is a minor UX glitch that I'm going to live with...