Skip to content

React JSX PPX: Support async components #6398

Closed
@zth

Description

@zth

With React server components, async React components are now a thing. Async components in this context means that you, on the server, can use an async function (and via that await in the body) as your component function:

let User = async (props) => {
   let userData = await getUserData(props.userId)
   <div>{userData.name}</div>
}

In ReScript it could look like this:

@react.component
let make = async (~userId) => {
  let userData = await getUserData(userId)
  <div> {React.string(userData.name)} </div>
}

However, this doesn't work today: https://rescript-lang.org/try?version=v11.0.0-beta.4&code=AIJwpghgxgLgdFA9gWwA6IHZgzAUAGzBgAJkIBrMYgXmIgGcBPDKYgCgD8BXesEASQAmAShoA+YgG9cxYoRI8+AEQgwINOgHcIASxIBzIgFVeIFWraKBImcQA8gnQDcJkgEqRYcejBA6M+pam5hBwGBDIYMIAvvYA9I4uuNG4QA
(I believe it doesn't work because we're loosing the async context in the PPX as the make function is transformed.)

It is possible to use async components today by not using the PPX, and defining your own wrapping identity function for casting the async component into a regular one:

type userData = {name: string}
let getUserData = async _userId => {name: "test"}

external asyncComponent: ('props => promise<React.element>) => React.component<
  'props,
> = "%identity"

module AsyncComponent = {
  type props = {userId: string}
  let make = asyncComponent(async (props: props) => {
    let userData = await getUserData(props.userId)
    <div> {React.string(userData.name)} </div>
  })
}

let jsx = <AsyncComponent userId="1" />

Playground for the above: https://rescript-lang.org/try?version=v11.0.0-beta.4&code=C4TwDgpgBArgzhATgEQIbFVAvFA3gO1QFsIAuKOYRAS3wHMBfAKABsJgo72BVBFdTDlRwQ+AMZQA+vCQBJACbYAfHkIlyAImARKG5kwgAPbYkIsow0WIDCAeyJhb+CPmDkAFAHIwiW2DjKUD721AgAPABKEKhiwAB0EGwkrkoAlIFRMfFi9o7OrmFMUFDevv4ANEwqOBoApNTyLsDUoBpMTES28jBsUACCIuJ2Dk5N2HhFUKCQQWUBOLgyiArklDT0zMVsHESoANbQQoM2uaOu7pbiUO7B-uS3cOlYKriTW+ywfGgY46gA7qgWpweF8BDc5nElgpUm8oGF5NQAG4vTKxOJrWh0dxLb6oOJqCCpBhwgD0CORkwYMP02ygACs4IZxmEBlZhnkxlD5FgNABGDRQElKJhAA

However, this gives up using the PPX, and requires you to manually wrap the make function in that external. And that doesn't feel very ergonomic.

How can we make this work?

I think this is important to support now that Server Components are becoming a thing, and ReScript supports everything else for them.

Interested in your thoughts here. The way I see it, we need at least 2 things:

  • Figure out why the async context isn't propagated as make is transformed in the PPX
  • Have some sort of functionality like the external above that turns an async component into a regular component that React/JSX expects. Maybe have this builtin to the PPX? Or ship that exact external with rescript-react?

Cc @mununki @cristianoc . What do you think? Interested in your thoughts of this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions