-
Notifications
You must be signed in to change notification settings - Fork 112
1247: Partial Tree Rerendering #1248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
a393b93 to
0514919
Compare
6f2d156 to
74fb6fb
Compare
0514919 to
7c724a3
Compare
74fb6fb to
c7d7c15
Compare
06bf903 to
e1f220c
Compare
0a36563 to
717d484
Compare
7d7098f to
b6e677c
Compare
| return flow.value | ||
| context.runningWorker(rerenderWorker) { output: T -> | ||
| action("rerenderUpdate") { | ||
| state = output |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prior to this state was not actually changing - so this would not work in the optimized runtime.
8647d68 to
e99c6b6
Compare
717d484 to
646ebf7
Compare
3a5f35a to
f888f1d
Compare
f888f1d to
f04cb3d
Compare
2a074ea to
b40368b
Compare
b40368b to
a3d67b6
Compare
2773b21 to
00eb7a6
Compare
| private fun updateCachedWorkflowInstance( | ||
| workflow: StatefulWorkflow<PropsT, StateT, OutputT, RenderingT> | ||
| ) { | ||
| ): Boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Add a note to the kdoc explaining this new return value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer returning as we just call this relying on its idempotency.
| !lastRendering.isInitialized || | ||
| subtreeStateDidChange | ||
| ) { | ||
| if (!didUpdateCachedInstance) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be simpler to just call updateCachedWorkflowInstance unconditionally here? It's idempotent, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, we check equality there, so we could call it again
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just call it again now.
| } | ||
|
|
||
| @JvmInline | ||
| internal value class Box<T>(private val _value: Any? = Uninitialized) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: This seems like a super generic and potentially useful helper, I'd pull it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracted into workflow-core as NullableInitBox with its own tests.
|
|
||
| @Suppress("UNCHECKED_CAST") | ||
| fun getOrThrow(): T { | ||
| check(isInitialized) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Give this a descriptive error message.
| setOf(CONFLATE_STALE_RENDERINGS, RENDER_ONLY_WHEN_STATE_CHANGES), | ||
| setOf(RENDER_ONLY_WHEN_STATE_CHANGES, PARTIAL_TREE_RENDERING), | ||
| setOf(CONFLATE_STALE_RENDERINGS, RENDER_ONLY_WHEN_STATE_CHANGES, PARTIAL_TREE_RENDERING), | ||
| ).asSequence() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in scope but… why isn't this just sequenceOf(…)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not sure tbh. the way it was written originally is likely just a mistake?
| // If we are using the optimization, always return to the parent, so we carry a path that | ||
| // notes that the subtree did change all the way to the root. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this comment, but I'm missing the middle reason why the optimization requires propagating change status all the way up but we don't need that without the optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need that without the optimization because there is nothing to output from the root of the runtime.
The output has propagated as far as it needs to causing all corresponding state changes.
However, the root and the path down to the changed nodes must always re-render now, so this is the implementation detail of how we get subtreeStateDidChange = true on that entire path to the root.
c1623df to
8f303c5
Compare
workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/RuntimeConfig.kt
Outdated
Show resolved
Hide resolved
workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/RuntimeConfig.kt
Outdated
Show resolved
Hide resolved
| * Applies [action] to this workflow's [state] and then passes the resulting [ActionApplied] | ||
| * via [emitAppliedActionToParent] to the parent, with additional information as to whether or | ||
| * not this action has changed the current node's state. | ||
| * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
snip
workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowNode.kt
Show resolved
Hide resolved
| * Check [isInitialized] to see if the value has been assigned. | ||
| */ | ||
| @JvmInline | ||
| public value class NullableInitBox<T>(private val _value: Any? = Uninitialized) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't take in at first that this is a value class. Cool!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was a @zach-klippenstein special when we were noodling on this.
If PARTIAL_TREE_RENDERING is in the RuntimeConfig then, Track whether or not the state (or state of a descendant) changed in the WorkflowNode. Pass lastRendering if its not. Also adds tests for this behavior and expands the test runtime matrix. Also adds shards for the new runtime for instrumentation tests.
…RuntimeConfig.kt Co-authored-by: Ray Ryan <[email protected]>
…RuntimeConfig.kt Co-authored-by: Ray Ryan <[email protected]>
…internal/WorkflowNode.kt Co-authored-by: Ray Ryan <[email protected]>
6384fa7 to
7d3a6fe
Compare
Re-render the node only if:
In order to do this, we have to propagate the action cascade all the way up to the root to record a single path of changed nodes.
Note we currently do not re-render if the workflow instance (the behavior definition instance, not the node) changed (unless the state also changed!), assuming the new workflow is still compatible with the old rendering because its identifier did not change.
Closes #1247.