Skip to content

Conversation

zach-klippenstein
Copy link
Collaborator

Part of #458.

renderAsState is a wrapper around the main workflow runtime entry point, renderWorkflowIn, that manages saving and restoring snapshot states as well as updating props and getting renderings and outputs from the workflow.

It's designed to follow the compose pattern for subscribing to reactive types: Flow.collectAsState(), LiveData.observeAsState(), Observable.subscribeAsState().

Example:

@Composable fun App(workflow: Workflow<…>, props: Props) {
  val scaffoldState =// Run the workflow in the current composition's coroutine scope.
  val rendering by workflow.renderAsState(props, onOutput = { output ->
    // Note that onOutput is a suspend function, so you can run animations
    // and call other suspend functions.
    scaffoldState.snackbarHostState
      .showSnackbar(output.toString())
  })
  val viewEnvironment = remember {
    ViewEnvironment(mapOf(ViewRegistry to appViewRegistry))
  }

  Scaffold(…) { padding ->
    // Display the root rendering using the view environment's ViewRegistry.
    WorkflowRendering(rendering, viewEnvironment, Modifier.padding(padding))
  }
}

@zach-klippenstein zach-klippenstein requested review from a team as code owners August 19, 2021 06:35
Copy link
Contributor

@steve-the-edwards steve-the-edwards left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple questions.

@rjrjr
Copy link
Collaborator

rjrjr commented Aug 19, 2021

I really want to use this in prod. 🤤

// the workflow runtime when it leaves the composition or if the composition doesn't commit.
// The remember is keyed on any values that we can't update the runtime with dynamically, and
// therefore require completely restarting the runtime to take effect.
val state = remember(workflow, scope, interceptors) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything that was hard about bootstrapping, Compose is making seamless. Thank God you came up with making the first rendering synchronous.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I'm still not sure this won't blow up on us. I would be honestly quite surprised if, with all the workflows we've written internally at this point, at least one isn't doing something in its initialState method that requires being on the main thread.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't want anyone to get bored.

@zach-klippenstein
Copy link
Collaborator Author

zach-klippenstein commented Aug 21, 2021

Should we put this in a dedicated compose-runtime module? As-is, this requires the workflow runtime to be a transitive dependency of any consumers that want to just define some ComposeViewFactorys.

This is marked as experimental, so I'm going to leave it here for now, and do the initial release this way, but if we want to move it out it won't be hard.

@zach-klippenstein
Copy link
Collaborator Author

Comments addressed, merging on green.

… composables.

Part of #458.

`renderAsState` is a wrapper around the main workflow runtime entry point, `renderWorkflowIn`, that manages saving and restoring snapshot states as well as updating props and getting renderings and outputs from the workflow.

It's designed to follow the compose pattern for subscribing to reactive types: `Flow.collectAsState()`, `LiveData.observeAsState()`, `Observable.subscribeAsState()`.

Example:
```kotlin
@composable fun App(workflow: Workflow<…>, props: Props) {
  val scaffoldState = …

  // Run the workflow in the current composition's coroutine scope.
  val rendering by workflow.renderAsState(props, onOutput = { output ->
    // Note that onOutput is a suspend function, so you can run animations
    // and call other suspend functions.
    scaffoldState.snackbarHostState
      .showSnackbar(output.toString())
  })
  val viewEnvironment = remember {
    ViewEnvironment(mapOf(ViewRegistry to appViewRegistry))
  }

  Scaffold(…) { padding ->
    // Display the root rendering using the view environment's ViewRegistry.
    WorkflowRendering(rendering, viewEnvironment, Modifier.padding(padding))
  }
}
```
@zach-klippenstein zach-klippenstein merged commit 587f12b into main Aug 21, 2021
@zach-klippenstein zach-klippenstein deleted the zachklipp/renderasstate branch August 21, 2021 01:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants