Lightning Application Events and Caching
Introduction
The lightning component framework has two types of event for intra-component communication:
- Component
Component events can be handled by the component that fired it, or any component above it in the containment hierarchy, so essentially any ancestor. - Application
Application events can be handled by any ancestor, but also have an additional propagation phase that allows any component to receive the events, assuming they’ve already registered.
I typically use application events in a broadcast scenario, where one of my components fires an event and a bunch of other components in my app receive it and take action. For example, when a user selects a value in a picklist and other components need to react to it. Which all worked fine until I had some cached pages.
Lightning Experience Caching
By default, the Lightning Experience will cache up to 5 last visited pages in order to speed up the browser back button. If I create a page that manages an account, and access this with the account id for Universal Contains and then AW Computing, both of these will be cached in the browser. This really speeds up performance, but has an unexpected side effect when using application events,
Even though the page managing Universal Containers is not visible, the components on it are still “live”. If my page has a custom component on it that receives application events, it will continue to receive application events while cached and not visible. This may not sound that bad, but in my case the component was receiving an event asking it to validate its contents and responding with another event to indicate the status. Both the component for AW Computing (that was visible) and the component for Universal Containers (that was not visible) received the event and responded to it.
Once this happened I was caught in a classic race condition - whichever one responded first would be taken as the current state of my component. As always seems to happen with race conditions, it was the worst outcome that prevailed most of the time. I would be working on the AW Computing page, in which the component was in an invalid state, but the Universal Containers component, which was in a valid state, would respond first and processing would proceed when it should have been blocked. What it looked like at the time was that duplicate events were being fired - tracking down what was actually happening was rather a challenge.
What to do?
Sadly there was no way for the component to know that it had been cached, everything about the visible one was the same as the invisible one. I did try a solution where I destroyed the component once the user navigated off the page, but that meant that if I used the back button the page was cached but the component missing, which meant the user had to refresh the page - also not a great experience.
The actual fix was to move away from application events in this case and use component events. As the communication was between a custom component and it’s parent, it all worked fine. If that hadn’t been the case then I’d probably have MacGyvered something where (un)rendering the component updated a window expando to indicate which version is actually “live” - it would work but I’d feel a bit dirty for having to resort to such tricks.
No comments:
Post a Comment