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

RFC: Intent to ship React 18 #212

Merged
merged 7 commits into from
Mar 28, 2022
Merged

RFC: Intent to ship React 18 #212

merged 7 commits into from
Mar 28, 2022

Conversation

rickhanlonii
Copy link
Member

@rickhanlonii rickhanlonii commented Mar 23, 2022

This RFC describes the changes we intend to ship in React 18 🎉

View formatted RFC

This RFC describes the changes we intend to ship in React 18.
@michaelwarren1106
Copy link

So since i'm not seeing any info about native support for web components in the RFC, does that mean that web component native support wont ship in React 18? If so, is there a rationale for that decision?

@gaearon
Copy link
Member

gaearon commented Mar 23, 2022

Re: #212 (comment)

So since i'm not seeing any info about native support for web components in the RFC, does that mean that web component native support wont ship in React 18? If so, is there a rationale for that decision?

It's available in the @experimental builds (and will continue to be available there), but we are going to put it into the next major stable release together with other DOM-related breaking changes that we've meant to do for years. It makes sense to batch them together. See facebook/react#11347 (comment) for more details.

@holloway
Copy link

If a library wants to support React 16/17/18 is there a recommended way of providing a useId fallback? Would it look something like (untested code)?:

import { useId } from 'react';

const useMyId = () => useId ? useId() : useState(uuid());

text/0000-react-18.md Outdated Show resolved Hide resolved
@rickhanlonii
Copy link
Member Author

Re: #212 (comment)

If a library wants to support React 16/17/18 is there a recommended way of providing a useId fallback?

There are libraries that do this pre-18, such as auto-id that you can use in 17 and below. We introduced useId in 18 because it's difficult for those libraries to support out-of-order streaming in 18. I would anticipate that existing libraries will switch to using useId if it's available so that all versions are supported.

text/0000-react-18.md Outdated Show resolved Hide resolved
text/0000-react-18.md Outdated Show resolved Hide resolved
Co-authored-by: Sebastian Silbermann <silbermann.sebastian@gmail.com>
@sonatard
Copy link

It looks like the Strict mode change is for the Offscreen API, will the Offscreen API be released in React 18?

@gaearon
Copy link
Member

gaearon commented Mar 24, 2022

Re: #212 (comment)

It looks like the Strict mode change is for the Offscreen API, will the Offscreen API be released in React 18?

Not in 18.0 but it’s one of the things we’ll be focusing on after 18.0 is out. So it will be out likely in some 18.x release if everything goes well.

@VanTanev
Copy link

VanTanev commented Mar 24, 2022

Sorry if this is addressed and I failed to find it, but is there a part of the RFC that expands on startTransition() vs useDeferredValue() - when to reach for one over the other and best practices for useDeferredValue()? I feel like startTransition() is explained very well, but useDeferredValue() (which I think in a sense is an alternative to startTransition() for simple use cases) hasn't been expanded upon.

@moshfiqrony
Copy link

I really liked the Automatic Batching feature. Is it something that we can turn or off for a project through package.json or it will be enable always? Can there be any situation where it will act like a bug?

@Moshyfawn
Copy link

Moshyfawn commented Mar 24, 2022

I really liked the Automatic Batching feature. Is it something that we can turn or off for a project through package.json or it will be enable always? Can there be any situation where it will act like a bug?

You can use the flushSync ReactDOM API to opt-out of batching.

From Automatic batching for fewer renders in React 18 write-up:

What if I don’t want to batch?

Usually, batching is safe, but some code may depend on reading something from the DOM immediately after a state change. For those use cases, you can use ReactDOM.flushSync() to opt out of batching:

import { flushSync } from 'react-dom'; // Note: react-dom, not react

function handleClick() {
  flushSync(() => {
    setCounter(c => c + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setFlag(f => !f);
  });
  // React has updated the DOM by now
}

@gaearon
Copy link
Member

gaearon commented Mar 24, 2022

Re: #212 (comment)

is there a part of the RFC that expands on startTransition() vs useDeferredValue() - when to reach for one over the other and best practices for useDeferredValue()?

No, this is an accidental omission. We'll try to write up something soon. The quick tldr is that useDeferredValue is similar to startTransition but with an API similar to userland useDebouncedValue helpers. It's useful when the value comes "from above" and you don't actually have control over the corresponding setState call. It is less clunky to use than startTransition but it has pitfalls similar to userland useDebouncedValue helpers (e.g. you have to use memoization for child components to get any benefit, and you need to be cautious to not pass always-new values into it to avoid loops).

@gaearon
Copy link
Member

gaearon commented Mar 24, 2022

Re: #212 (comment)

I really liked the Automatic Batching feature. Is it something that we can turn or off for a project through package.json or it will be enable always?

No, you can't configure it. As @Moshyfawn described in #212 (comment) though, you can opt out of it for a specific setState call if you need to observe the modified DOM synchronously.

@nafg
Copy link

nafg commented Mar 24, 2022

Is there any way to get the benefits of the server integration without a node.js backend? I guess the applies to traditional SSR but is there a wire protocol spec (not sure if this is just a matter of a JSON schema or something more)? If not I think it would be great if there was. Then there could be backends in other languages that support "isomorphic apps." For instance I develop in Scala, using Scala.js to compile the frontend and scalajs-react to build React UIs. But right now the only way I know of to get SSR in Scala involves a complicated setup. If the new server features, as well as traditional SSR, would have a wire spec then alternative backends could be written in other languages.

@gaearon
Copy link
Member

gaearon commented Mar 24, 2022

Re: #212 (comment)

The main value proposition of both SSR and Server Components is that you get to run the same own component code on the backend. In principle, nothing stops you from emulating the payload React generates (e.g. by running Scala versions of your components and reimplementing the React server renderer), but there are no current plans to standardize the payload.

@nafg
Copy link

nafg commented Mar 24, 2022

Re: #212 (comment)

The main value proposition of both SSR and Server Components is that you get to run the same own component code on the backend. In principle, nothing stops you from emulating the payload React generates (e.g. by running Scala versions of your components and reimplementing the React server renderer), but there are no current plans to standardize the payload.

If it was, the Scala vdom DSL could easily be implemented in a way that it would do different things on the JVM backend vs. the JS frontend. So this benefit could still be achieved with a much simpler setup if only the payload was specified.

@gaearon
Copy link
Member

gaearon commented Mar 25, 2022

If it was, the Scala vdom DSL could easily be implemented in a way that it would do different things on the JVM backend vs. the JS frontend. So this benefit could still be achieved with a much simpler setup if only the payload was specified.

We don't specify the exact payload protocol because there is a lot of benefit to being able to change it midway without bumping versions. So I don't see that happening. In practice, the HTML output we produce is relatively stable and usually matches what you'd expect, aside from a few special instructions (like for Suspense). The most pragmatic solution, if you really wanted to do something like this, is to take our test suite and run your implementation against it. Since you're probably going to want to recreate other behaviors (like actual rendering of components according to React rules!) too. So if you're running against our test suite, you can consider that to be the specification. Then as long as you use the same version of React as the version that the tests were written against, it should work well. Tests are the source of truth for us, too.

text/0000-react-18.md Outdated Show resolved Hide resolved
@gaearon
Copy link
Member

gaearon commented Mar 25, 2022

We've added reactwg/react-18#129 with an explanation of useDeferredValue, and reactwg/react-18#129 (reply in thread) with a small concrete example.

@rickhanlonii
Copy link
Member Author

Update: I've added useDeferredValue to this RFC, my mistake for forgetting it!

@rickhanlonii
Copy link
Member Author

Also included here are all the docs we are adding and changing on the website: reactjs/react.dev#4499.

For a preview, see: https://18-preview.reactjs.org.

@trhinehart-godaddy
Copy link

Is there a pattern or plans for adding startTransition() into Suspense to mimic a "delay" before showing a fallback? Other libs like react-loadable and @loadable/component try to address the issue but could only render null instead of use a feature like startTransition() to keep the existing DOM intact and interactive.

@gaearon
Copy link
Member

gaearon commented Mar 28, 2022

Re: #212 (comment)

Is there a pattern or plans for adding startTransition() into Suspense to mimic a "delay" before showing a fallback? Other libs like react-loadable and @loadable/component try to address the issue but could only render null instead of use a feature like startTransition() to keep the existing DOM intact and interactive.

startTransition does work together with <Suspense>, as described here. However, you can't have it "wait" and then "switch". Instead, we decide on the behavior depending on whether the <Suspense> boundary is newly created or already shown. If it's newly created during a transition, we show fallback immediately. But if it was already shown before, we wait for it to complete because we don't want to "hide" already shown content.

There is no way to get a behavior where we first "wait" and then show the fallback after a timeout. We used to provide that ability but removed it. We found that in practice there's no concrete meaningful number one can specify (one second? three seconds? ten? how to choose?) and it ends up being a confusing user experience (the switch to fallback implies some kind of a change but there was no actual change). We think the current heuristic with consistent behavior for "new" vs "existing" boundaries works better in practice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.