@@ -96,7 +96,12 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
96
96
private val eventActionsChannel =
97
97
Channel <WorkflowAction <PropsT , StateT , OutputT >>(capacity = UNLIMITED )
98
98
private var state: StateT
99
- private var subtreeStateDidChange: Boolean = true
99
+
100
+ // Our state or that of one of our descendants changed.
101
+ private var subtreeStateDirty: Boolean = true
102
+
103
+ // Our state changed.
104
+ private var selfStateDirty: Boolean = true
100
105
101
106
private val baseRenderContext = RealRenderContext (
102
107
renderer = subtreeManager,
@@ -209,16 +214,27 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
209
214
* time of suspending.
210
215
*/
211
216
@OptIn(ExperimentalCoroutinesApi ::class , DelicateCoroutinesApi ::class )
212
- fun onNextAction (selector : SelectBuilder <ActionProcessingResult >): Boolean {
213
- // Listen for any child workflow updates.
214
- var empty = subtreeManager.onNextChildAction(selector)
217
+ fun onNextAction (
218
+ selector : SelectBuilder <ActionProcessingResult >,
219
+ skipChangedNodes : Boolean = false
220
+ ): Boolean {
221
+ var empty = if (! skipChangedNodes || ! selfStateDirty) {
222
+ // Listen for any child workflow events.
223
+ subtreeManager.onNextChildAction(selector, skipChangedNodes)
224
+ } else {
225
+ // Our state changed and we are skipping changed nodes, so our actions are empty from
226
+ // this node down.
227
+ true
228
+ }
215
229
216
230
empty = empty && (eventActionsChannel.isEmpty || eventActionsChannel.isClosedForReceive)
217
231
218
- // Listen for any events.
219
- with (selector) {
220
- eventActionsChannel.onReceive { action ->
221
- return @onReceive applyAction(action)
232
+ if (! skipChangedNodes || ! selfStateDirty) {
233
+ // Listen for any events.
234
+ with (selector) {
235
+ eventActionsChannel.onReceive { action ->
236
+ return @onReceive applyAction(action)
237
+ }
222
238
}
223
239
}
224
240
return empty
@@ -264,7 +280,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
264
280
265
281
if (! runtimeConfig.contains(PARTIAL_TREE_RENDERING ) ||
266
282
! lastRendering.isInitialized ||
267
- subtreeStateDidChange
283
+ subtreeStateDirty
268
284
) {
269
285
// If we haven't already updated the cached instance, better do it now!
270
286
maybeUpdateCachedWorkflowInstance(workflow)
@@ -284,7 +300,8 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
284
300
}
285
301
// After we have rendered this subtree, we need another action in order for us to be
286
302
// considered dirty again.
287
- subtreeStateDidChange = false
303
+ subtreeStateDirty = false
304
+ selfStateDirty = false
288
305
}
289
306
290
307
return lastRendering.getOrThrow()
@@ -293,7 +310,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
293
310
/* *
294
311
* Update props if they have changed. If that happens, then check to see if we need
295
312
* to update the cached workflow instance, then call [StatefulWorkflow.onPropsChanged] and
296
- * update the state from that. We consider any change to props as [subtreeStateDidChange] because
313
+ * update the state from that. We consider any change to props as dirty because
297
314
* the props themselves are used in [StatefulWorkflow.render] (they are the 'external' part of
298
315
* the state) so we must re-render.
299
316
*/
@@ -305,7 +322,8 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
305
322
maybeUpdateCachedWorkflowInstance(workflow)
306
323
val newState = interceptedWorkflowInstance.onPropsChanged(lastProps, newProps, state)
307
324
state = newState
308
- subtreeStateDidChange = true
325
+ subtreeStateDirty = true
326
+ selfStateDirty = true
309
327
}
310
328
lastProps = newProps
311
329
}
@@ -327,8 +345,10 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
327
345
// Changing state is sticky, we pass it up if it ever changed.
328
346
stateChanged = actionApplied.stateChanged || (childResult?.stateChanged ? : false )
329
347
)
348
+ // Our state changed.
349
+ selfStateDirty = actionApplied.stateChanged
330
350
// Our state changed or one of our children's state changed.
331
- subtreeStateDidChange = aggregateActionApplied.stateChanged
351
+ subtreeStateDirty = aggregateActionApplied.stateChanged
332
352
return if (actionApplied.output != null ||
333
353
runtimeConfig.contains(PARTIAL_TREE_RENDERING )
334
354
) {
@@ -341,7 +361,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
341
361
//
342
362
// However, the root and the path down to the changed nodes must always
343
363
// re-render now, so this is the implementation detail of how we get
344
- // subtreeStateDidChange = true on that entire path to the root.
364
+ // subtreeStateDirty = true on that entire path to the root.
345
365
emitAppliedActionToParent(aggregateActionApplied)
346
366
} else {
347
367
aggregateActionApplied
0 commit comments