Best Practices for Reactivity in Screen Flows (Beta)
Ensure your Lightning web components integrate well within the Flow runtime engine and work as expected for Screen Flow reactivity.
These sections describe state management with reactivity in Screen Flows, including:
- How LWC state management differs from Aura
- How state management works in the new LWC Flow Runtime
- State management and event best practices to follow when building LWCs for your screen flows
State management for Aura components and LWCs follow different paradigms. In Aura components, <aura:attributes />
are viewed and modified by the component to which they belong, including external components. LWCs are designed to have a clear separation between internal and external states. Variables declared with @api
are intended to be modified only by the LWC’s parents. Variables without the @api
annotation and variables with @track
are considered internal states and can be changed within the LWC that defines them.
The Flow runtime adheres to LWC state management design principles. It works best when the LWC components that it renders do not modify their own @api
attributes. Instead, components request a change by firing FlowAttributeChangeEvent
, which is essential for several reasons.
- Components that allow their parents to control their
@api
properties are more easily reused because they allow the application to control the state rather than the component’s own internal business logic. - By firing attribute change events, the Flow runtime maintains an accurate picture of the component state. The Flow runtime can control inter-component interactions such as conditional field visibility, which is part of reactivity.
Using LWC linter rules is an excellent way to ensure that your component does not modify @api
properties. Set up a linter that uses LWC’s linter rules in your development environment, specifically ensuring that the setting is enforced.
To maintain consistent behavior between Flow Runtime versions, when a user clicks the Next or Finish button, the Flow Runtime collects values by extracting each custom LWC component’s current @api
attribute state before moving to the next screen or finishing the flow. This mechanism ensures that components that do not adhere to the prescribed design pattern continue to work in the latest Flow Runtime version. It is strongly recommended to avoid relying on this behavior.
Here is an example of a simple text input component that demonstrates firing FlowAttributeChangeEvent
instead of updating the LWC’s @api
property:
The following example isn’t recommended.
The FlowAttributeChangeEvent
event provides LWCs the ability to inform the runtime of their current state. It is part of Flow Runtime’s state management mechanism. These events are meant to be fired whenever user interaction results in a modification that requires an update to an @api
property.
Import FlowAttributeChangeEvent
from the lightning/flowSupport
module.
Next, you can create an instance of the event.
FlowAttributeChangeEvent
includes two arguments.
apiParameterName
—The name of the API property to modify.updatedValue
—The updated value for the Flow attribute.
Pass a string to apiParameterName
that matches the API property as it appears in the JavaScript and .js-meta.xml
files.
For example, notice how exampleApiParameterName
is consistent in all 3 places:
-
Declare the attribute in the LWC’s
.js-meta.xml
file: -
Declare the API property in the LWC’s
.js
file: -
Construct the
FlowAttributeChangeEvent
instance:
Pass the updatedValue
to match the declared datatype in the .js-meta.xml
file.
-
Declare the property as a Record:
-
Declare the property as a string:
-
Declare the property as a number:
-
Declare the property as a boolean:
After constructing a FlowAttributeChangeEvent
instance, you can fire the event using the this.dispatchEvent(eventToFire)
method.
Follow these FlowAttributeChangeEvent
examples and steer clear of problematic usages to reduce unexpected behaviors after a flow version upgrade. These best practices enable you to maintain your components more easily.
- Fire events in event handlers or in methods invoked within event handlers.
- Limit an event’s value parameter to the following datatypes: String, number, boolean, JSON (for record types).
- Ensure that the Flow datatype of the event’s value parameter matches the datatype of the LWC’s
@api
property. - React to changes to
@api
properties by using a get/set pattern where appropriate.
This example demonstrates using a getter and setter to count the updates with an @api
property vs. incrementing a counter before firing an attribute change event. Both patterns are valid, but they achieve slightly different results.
In this case, this.changeCounter
is incremented whenever the user enters a change in the text input and whenever the Flow Runtime determines that the textValue
property has changed. This approach accounts for component initialization and cross-component interactions via reactivity. Use an intermediate variable to render updates from the set method. In this example, textValueToRender
fills this role.
The following code example increments a counter before firing an attribute change event. This scenario doesn’t use the get/set pattern.
In this case, this.changeCounter
is incremented whenever the user inputs a change in the text input. The counter does not update when reactivity changes the value of this field.
Use annotationless or @track
properties to maintain a modifiable local component state.
The following example shows a color picker that presents the user with an input text box and some swatches. The color picker component returns color
to the flow, so only color
needs the @api
annotation. The selectedSwatchId
and inputValue
members are internal only and do not need any decorator.
Use a get method to combine multiple @api
properties together to construct a derived variable for the view.
Apply the same logic in the set method of every @api
property that contributes to a derived member variable needed for internal component state management, as in more complex scenarios than the previous example. This logic ensures that a change made to any contributing attribute causes the value to render correctly regardless of the order of the set attributes.
Don’t modify @api
properties. Fire FlowAttributeChangeEvents
instead.
Don’t modify FlowAttributeChangeEvent
parameters after construction. By default, FlowAttributeChangeEvent
instances are composed and bubble.
Avoid firing FlowAttributeChangeEvents
and FlowNavigationXxx
events at the same time as it can lead to race conditions. There's never a guarantee that your Lightning web component has had time to render the updated values by the time the navigation process is started.
In addition to FlowAttributeChangeEvent
, your Lightning web components can fire navigation events to move between screens, pause, or finish flows. To work with navigation events, import these functions from lightning/flowSupport
:
FlowNavigationNextEvent
FlowNavigationBackEvent
FlowNavigationPauseEvent
FlowNavigationFinishEvent
This snippet describes how to import and fire a navigation event. While the example uses FlowNavigationNextEvent
, the same structure holds for each of the available navigation targets.
Navigation events allow your Lightning web components to include additional control mechanisms. Fire navigation events when reacting to end-user interactions. Refer to these guidelines when using navigation events:
- Fire navigation events in event handlers (or in the method they invoke).
- Don’t fire navigation events outside of event handlers because it leads to a poor user experience.
- Don’t fire navigation events in lifecycle handlers like
renderedCallback
andconnectedCallback
. - Place the logic for skipping screens in Flow Decision Nodes, not in the lifecycle of a screen.
- Don’t perform navigation in a dummy screen because it can lead to poor Flow performance.
- If you encounter a scenario where navigation must be done within the initialization phase of the screen because data isn’t yet available to Flow Decision Nodes, post a request for an upgrade in Idea Exchange