@@ -93,7 +93,12 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
93
93
private val eventActionsChannel =
94
94
Channel <WorkflowAction <PropsT , StateT , OutputT >>(capacity = UNLIMITED )
95
95
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
97
102
98
103
private val baseRenderContext = RealRenderContext (
99
104
renderer = subtreeManager,
@@ -181,16 +186,27 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
181
186
* time of suspending.
182
187
*/
183
188
@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
+ }
187
201
188
202
empty = empty && (eventActionsChannel.isEmpty || eventActionsChannel.isClosedForReceive)
189
203
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
+ }
194
210
}
195
211
}
196
212
return empty
@@ -236,7 +252,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
236
252
237
253
if (! runtimeConfig.contains(PARTIAL_TREE_RENDERING ) ||
238
254
! lastRendering.isInitialized ||
239
- subtreeStateDidChange
255
+ subtreeStateDirty
240
256
) {
241
257
// If we haven't already updated the cached instance, better do it now!
242
258
maybeUpdateCachedWorkflowInstance(workflow)
@@ -255,7 +271,8 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
255
271
}
256
272
// After we have rendered this subtree, we need another action in order for us to be
257
273
// considered dirty again.
258
- subtreeStateDidChange = false
274
+ subtreeStateDirty = false
275
+ selfStateDirty = false
259
276
}
260
277
261
278
return lastRendering.getOrThrow()
@@ -264,7 +281,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
264
281
/* *
265
282
* Update props if they have changed. If that happens, then check to see if we need
266
283
* 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
268
285
* the props themselves are used in [StatefulWorkflow.render] (they are the 'external' part of
269
286
* the state) so we must re-render.
270
287
*/
@@ -276,7 +293,8 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
276
293
maybeUpdateCachedWorkflowInstance(workflow)
277
294
val newState = interceptedWorkflowInstance.onPropsChanged(lastProps, newProps, state)
278
295
state = newState
279
- subtreeStateDidChange = true
296
+ subtreeStateDirty = true
297
+ selfStateDirty = true
280
298
}
281
299
lastProps = newProps
282
300
}
@@ -298,8 +316,10 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
298
316
// Changing state is sticky, we pass it up if it ever changed.
299
317
stateChanged = actionApplied.stateChanged || (childResult?.stateChanged ? : false )
300
318
)
319
+ // Our state changed.
320
+ selfStateDirty = actionApplied.stateChanged
301
321
// Our state changed or one of our children's state changed.
302
- subtreeStateDidChange = aggregateActionApplied.stateChanged
322
+ subtreeStateDirty = aggregateActionApplied.stateChanged
303
323
return if (actionApplied.output != null ||
304
324
runtimeConfig.contains(PARTIAL_TREE_RENDERING )
305
325
) {
0 commit comments