Skip to content
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

feat(jsx/dom): Compatible implementation of new features in React 19 (document metadata, "form" element and related hooks, and new behavior of hooks) #2960

Merged
merged 52 commits into from
Jun 21, 2024

Conversation

usualoma
Copy link
Member

@usualoma usualoma commented Jun 11, 2024

#2959

Implemented features by this pull request

Other changes or refactoring that require explanation

Some incompatibilities (in the ~18 API) were resolved in the support for React 19. Other changes not directly related to React 19 compatibility improvements are also included and are discussed below.

compatibility of use() hook

In hono's jsx, the following code had a behaviour where it would continue to return the result of the first promise even if a different promise was passed, which was incompatible and has been fixed.

https://github.com/honojs/hono/pull/2960/files#diff-00be452f071d90d2904b8acdd0b15dc607fee092c4545b38387e2f52a6eba35fR63-R95

compatibility of useDeferredValue

useDeferredValue was not implemented correctly and has been newly rewritten for compatible behaviour.

The process of updating by setState has been simplified

The following 'processing in shadows' was not actually necessary and was useless code, so it was removed. I think the new way of doing things is correct, as all tests pass and no problems occur when checking in the browser.

https://github.com/honojs/hono/pull/2960/files#diff-1157fd5461da22f1e5982c5351a7f913bb8b7812d25f97c212bd7b7417344b62L192-L200

add "dom.iterable" to deno.react-jsx.json

The following code is fine in modern browsers, but TypeScript reports an error if there is no "dom.iterable" in the "libs", so I added it.

https://github.com/honojs/hono/pull/2960/files#diff-7c151a16ca64f89d875c682a551d8242736846e67198c3bc08e2802679dcaca0R119

https://github.com/honojs/hono/pull/2960/files#diff-9a67da5b07fb7e04bdbf99e1f78eca536e036cfd58553557d18fcd7b0b3da34bL7-R8

Introduce internal API resolveCallbackSync

Added this API to insert meta data tags in the head (needed in stringify, not in dom).

https://github.com/honojs/hono/pull/2960/files#diff-fe7471a671ed7be8aefd96aacb37be7ff93c8f65c2749d64f4eb86b3c2c8e916R128-R140

We could have achieved this with Promise in the past, but this time we wanted something that could be resolved synchronously, so we added a new API in this pull request to handle it. What we are doing is almost the same as resolveCallback. Implemented in such a way that there is no performance deviation for existing users who use simple jsx on the server side.

The author should do the following, if applicable

  • Add tests
  • Run tests
  • bun run format:fix && bun run lint:fix to format the code
  • Add TSDoc/JSDoc to document the code

@usualoma usualoma changed the base branch from main to react-19-compat June 11, 2024 21:35
@usualoma usualoma marked this pull request as ready for review June 16, 2024 08:19
@usualoma
Copy link
Member Author

@yusukebe I'm sorry it's such a big pull request, but could you please review it? I think this covers most of the new APIs in Ract 19.

@yusukebe
Copy link
Member

@usualoma Okay! I'll do it later.

@usualoma
Copy link
Member Author

Hi @yusukebe
Sorry, I found that there are some larger incompatibilities, which I have fixed in usualoma#5 and merged into this pull request. I will not add any changes until the review is complete.

@yusukebe
Copy link
Member

@usualoma

Thanks. I'm now reviewing it.

@yusukebe
Copy link
Member

Hi @usualoma

Awesome for such a hard work! I've taken a look at the code and tried examples for the new feature with these updates. There is one issue I could find.

useTransition()

First return value like isPending from useTranstion() is not working correctly with a disable attribute:

function Update() {
  const [isPending, startTransition] = useTransition()

  const handleSubmit = () => {
    startTransition(async () => {
      await new Promise((resolve) => setTimeout(resolve, 1000))
      console.log(`done!`)
    })
  }

  return (
    <div>
      <button onClick={handleSubmit} disabled={isPending}>
        Update
      </button>
    </div>
  )
}
Area.mp4

formAction

And it's not a bug, but will you implement formAction attribute? Like the following code:

function Form() {
  const action = () => {
    console.log('action!')
  }
  return (
    <form>
      <button formAction={action}>Increment</button>
    </form>
  )
}

Anyway, almost everything works fine, though I may be missing something. Great!

@usualoma
Copy link
Member Author

It is still a work in progress as it does not handle asynchronous errors.

@usualoma
Copy link
Member Author

Hi @yusukebe

  • async function to useTransition
  • formAction

Each of these has been impremented.

The handling of ErrorBoudnary and Suspense in general has been improved so that use() now works correctly when used deep inside Suspense.

Please review!

Copy link
Member

@yusukebe yusukebe left a comment

Choose a reason for hiding this comment

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

LGTM!

@yusukebe
Copy link
Member

Hi @usualoma

Looks good to me!

One thing. Can we title this PR (or a commit message with a squash merging to the main) "Introduce document metadata integration"? I think this PR does not only "document metadata matter".

@usualoma
Copy link
Member Author

@yusukebe Thank you for reviewing!

Yes, that's true. I'm sorry I put so many things in there, but if I were to describe the pull request correctly, how about this, even though it's a bit long?

feat(jsx/dom): Compatible implementation of new features in React 19 (document metadata, "form" element and related hooks, and new behavior of hooks)

@yusukebe yusukebe changed the title feat(jsx/dom): Introduce document metadata integration for compatibility with React 19 feat(jsx/dom): Compatible implementation of new features in React 19 (document metadata, "form" element and related hooks, and new behavior of hooks) Jun 21, 2024
@yusukebe
Copy link
Member

@usualoma

feat(jsx/dom): Compatible implementation of new features in React 19 (document metadata, "form" element and related hooks, and new behavior of hooks)

That sounds good! I've updated this PR title and will merge it with the title, though GitHub will trim it.

@yusukebe yusukebe merged commit a734b35 into honojs:react-19-compat Jun 21, 2024
14 checks passed
@usualoma usualoma deleted the feat/jsx-document-metadata branch June 21, 2024 23:39
@usualoma
Copy link
Member Author

@yusukebe Thank you 🚅

yusukebe pushed a commit that referenced this pull request Jun 27, 2024
…(document metadata, "form" element and related hooks, and new behavior of hooks) (#2960)

* feat(jsx/dom): Introduce document metadata integration for compatibility with React 19

* test(jsx/dom): add test for "ref as a prop"

* refactor: tweaks element selector

* feat(jsx/dom): implement " Cleanup functions for refs" for compatibility with React 19

* feat(jsx/dom): implement `useDeferredValue()`

* refactor(jsx): insert metadata into head synchronously

* feat(jsx/dom): introduce form and related hooks

* feat(jsx): sort by precedence in documentMetadataTag

* feat(jsx): enable to specify action attribute as function

* fixup! feat(jsx): enable to specify action attribute as function

* refactor: refactor file layout

* feat(jsx): de-dupe tags

* feat(jsx): accept crossOrigin as crossorigin

* feat(jsx/dom): inprement blocking and precedence feature for jsx/dom

* feat(jsx): export new hooks

* fix(jsx/dom): fix some bugs in jsx/dom/hooks

* fix(jsx/dom): fix useOptimistic hook

* fix(jsx/dom): fix signature of useActionState

* fix(jsx): fix type declaration for HtmlEscapedCallback

* refactor(jsx): improve importing of intrinsic element components

* feat(jsx): support permalink for useActionState

* fix(jsx): fix composeRef cleanup in intrinsic element components

* fix(jsx): remove blocking attribute from DOM node

* fix(jsx/dom): preserve HTMLElement for meta data if it will be unmounted

* fix(jsx/dom): fix de-dupe logic in `documentMetadataTag`

* fix(jsx/dom): fix precedence logic in `documentMetadataTag`

* feat(jsx): add React 19 compatibility attributes

* fix(jsx): Handle NodeListOf<HTMLElement> as an iterable

* test: tweaks test data

* fix(jsx/dom): fix precedence logic in `documentMetadataTag`

* fix(jsx/dom): fix meta data tag insertion behavior

* fix(jsx/dom): set next node recursively for all previous nodes

* refactor(jsx/dom): use better variable names and types in form component

* fix(jsx/dom): fix meta data tag insertion behavior

* fix(jsx): improve document meta tag behavior in jsx

* test(jsx/dom): add tests for intrinsic-element/components

* fix(jsx/dom): fix `use()` hook wrong behavior

* test(jsx/dom): add tests for hooks

* test(jsx): add tests new hooks for form

* fix(jsx): update current state synchronously if no actions are provided

* test(jsx): add tests for new hooks for form handling

* docs(jsx): add documentation for hooks

* test(jsx): Update test

* refactor(jsx/hooks): remove unused constant

* feat(jsx): improve compatibility with React 19 (precedence / special behavior)

* feat(jsx/dom): improve compatibility with title element mount/unmount behavior

* feat(jsx): support async function for useTransition

* fix(jsx/dom): method is always 'post' when data is present

* feat(jsx): support formAction for input and button elements

* feat(jsx/dom): support suspense with child counter

* feat(jsx/dom): enable to handle async error in useTransition
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.

2 participants