@@ -93,7 +93,12 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
9393 private val eventActionsChannel =
9494 Channel <WorkflowAction <PropsT , StateT , OutputT >>(capacity = UNLIMITED )
9595 private var state: StateT
96- private var subtreeStateDidChange: Boolean = true
96+
97+ // Our state or that of one of our descendants changed.
98+ private var subtreeStateDirty: Boolean = true
99+
100+ // Our state changed.
101+ private var selfStateDirty: Boolean = true
97102
98103 private val baseRenderContext = RealRenderContext (
99104 renderer = subtreeManager,
@@ -181,16 +186,27 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
181186 * time of suspending.
182187 */
183188 @OptIn(ExperimentalCoroutinesApi ::class , DelicateCoroutinesApi ::class )
184- fun onNextAction (selector : SelectBuilder <ActionProcessingResult >): Boolean {
185- // Listen for any child workflow updates.
186- var empty = subtreeManager.onNextChildAction(selector)
189+ fun onNextAction (
190+ selector : SelectBuilder <ActionProcessingResult >,
191+ skipChangedNodes : Boolean = false
192+ ): Boolean {
193+ var empty = if (! skipChangedNodes || ! selfStateDirty) {
194+ // Listen for any child workflow events.
195+ subtreeManager.onNextChildAction(selector, skipChangedNodes)
196+ } else {
197+ // Our state changed and we are skipping changed nodes, so our actions are empty from
198+ // this node down.
199+ true
200+ }
187201
188202 empty = empty && (eventActionsChannel.isEmpty || eventActionsChannel.isClosedForReceive)
189203
190- // Listen for any events.
191- with (selector) {
192- eventActionsChannel.onReceive { action ->
193- return @onReceive applyAction(action)
204+ if (! skipChangedNodes || ! selfStateDirty) {
205+ // Listen for any events.
206+ with (selector) {
207+ eventActionsChannel.onReceive { action ->
208+ return @onReceive applyAction(action)
209+ }
194210 }
195211 }
196212 return empty
@@ -236,7 +252,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
236252
237253 if (! runtimeConfig.contains(PARTIAL_TREE_RENDERING ) ||
238254 ! lastRendering.isInitialized ||
239- subtreeStateDidChange
255+ subtreeStateDirty
240256 ) {
241257 // If we haven't already updated the cached instance, better do it now!
242258 maybeUpdateCachedWorkflowInstance(workflow)
@@ -255,7 +271,8 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
255271 }
256272 // After we have rendered this subtree, we need another action in order for us to be
257273 // considered dirty again.
258- subtreeStateDidChange = false
274+ subtreeStateDirty = false
275+ selfStateDirty = false
259276 }
260277
261278 return lastRendering.getOrThrow()
@@ -264,7 +281,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
264281 /* *
265282 * Update props if they have changed. If that happens, then check to see if we need
266283 * to update the cached workflow instance, then call [StatefulWorkflow.onPropsChanged] and
267- * update the state from that. We consider any change to props as [subtreeStateDidChange] because
284+ * update the state from that. We consider any change to props as dirty because
268285 * the props themselves are used in [StatefulWorkflow.render] (they are the 'external' part of
269286 * the state) so we must re-render.
270287 */
@@ -276,7 +293,8 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
276293 maybeUpdateCachedWorkflowInstance(workflow)
277294 val newState = interceptedWorkflowInstance.onPropsChanged(lastProps, newProps, state)
278295 state = newState
279- subtreeStateDidChange = true
296+ subtreeStateDirty = true
297+ selfStateDirty = true
280298 }
281299 lastProps = newProps
282300 }
@@ -298,8 +316,10 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
298316 // Changing state is sticky, we pass it up if it ever changed.
299317 stateChanged = actionApplied.stateChanged || (childResult?.stateChanged ? : false )
300318 )
319+ // Our state changed.
320+ selfStateDirty = actionApplied.stateChanged
301321 // Our state changed or one of our children's state changed.
302- subtreeStateDidChange = aggregateActionApplied.stateChanged
322+ subtreeStateDirty = aggregateActionApplied.stateChanged
303323 return if (actionApplied.output != null ||
304324 runtimeConfig.contains(PARTIAL_TREE_RENDERING )
305325 ) {
0 commit comments