Replacing render with createRoot #5
Replies: 8 comments 31 replies
-
Is it recommended that folks using |
Beta Was this translation helpful? Give feedback.
-
Thanks for the clarification, @rickhanlonii. It's really nice to see the considerations invested into the root API change. I like that you jump right to it with terms: I haven't used the |
Beta Was this translation helpful? Give feedback.
-
Thanks for writing this down. It was one of the concerns that immediately jumped out when working on concurrent rendering in Though this new API feels more awkward for our particular use case. In the default use case we create the container on the fly and already solve the "you don't need to constantly pass a container" problem. But now we have to make sure we're always keeping the container and root together (since we need to cleanup the container) which seems brittle to me. And then there's So for |
Beta Was this translation helpful? Give feedback.
-
The callback example is great! In Gatsby we've now implemented it as a
|
Beta Was this translation helpful? Give feedback.
-
We've just made changes to hydration in the latest alpha cut. Specifically, This allows to clearly separate the hydration-only options from general |
Beta Was this translation helpful? Give feedback.
-
Update: we will now warn when using See facebook/react#21652 for more details. |
Beta Was this translation helpful? Give feedback.
-
How would I know when this hydration is completed? For example, the following naive approach currently issues a hydration warning: const ui = <input />;
const container = document.getElementById("root");
container.innerHTML = renderToString(ui);
const root = hydrateRoot(container, ui);
root.render(<h1 />); I could imagine a UI that calls |
Beta Was this translation helpful? Give feedback.
-
Hey friends! There's "react-callback" implementation that I see making the rounds that I was hoping to get a sense for here. In an effort to return a ref, without inserting a wrapping element, it does the following:
https://github.com/Tyson-Skiba/react-callback/blob/main/index.tsx#L1-L26 // https://github.com/Tyson-Skiba/react-callback/blob/main/index.tsx#L1-L26
type Callback = (() => void) | undefined;
interface CallbackProps {
callback?: Callback;
children: React.ReactChild | React.ReactNodeArray;
}
const onMount = (element: HTMLDivElement | null, callback: Callback) => {
if (callback) callback();
if (element && element.parentElement) element.parentElement.removeChild(element);
}
export const CallbackWrapper: React.FC<CallbackProps> = ({
callback,
children
}) => (
<>
{ children }
<div
ref={element => onMount(element, callback)}
style={{ display: 'none' }}
/>
</>
) I guess my big question is: is there a case where this is actually a recommended practice? In this case, the returned DOM element has no utility. |
Beta Was this translation helpful? Give feedback.
-
Overview
React 18 ships two root APIs, which we call the Legacy Root API and the New Root API.
ReactDOM.render
. This creates a root running in “legacy” mode, which works exactly the same as React 17. Before release, we will add a warning to this API indicating that it’s deprecated and to switch to the New Root API.ReactDOM.createRoot
. This creates a root running in React 18, which adds all of the improvements of React 18 and allows you to use concurrent features. This will be the root API moving forward.Note: the New Root API is available by importing
react-dom/client
:For more information see #125.
What is a root?
In React, a “root” is a pointer to the top-level data structure that React uses to track a tree to render. In the legacy API, the root was opaque to the user because we attached it to the DOM element, and accessed it through the DOM node, never exposing it to the user:
In the New Root API, the caller creates a root and then calls render on it:
What are the differences?
There are a few reasons we changed the API.
First, this fixes some of the ergonomics of the API when running updates. As shown above, in the legacy API, you need to continue to pass the container into render, even though it never changes. This also mean that we don’t need to store the root on the DOM node, though we still do that today.
Second, this change allows us to remove the
hydrate
method and replace with with an option on the root; and remove the render callback, which does not make sense in a world with partial hydration.What about hydration?
We’ve moved the
hydrate
function to ahydrateRoot
API.Before:
After:
Note that unlike
createRoot
,hydrateRoot
accepts the initial JSX as the second argument. This is because the initial client render is special and needs to match with the server tree.If you want to update a root again after hydration, you can save it to a variable, just like with
createRoot
, and callroot.render()
later:What about the render callback?
In the legacy root API, you could pass
render
a callback that is called after the component is rendered or updated:In the New Root API, we’ve removed this callback.
With partial hydration and progressive SSR, the timing for this callback would not match what the user expects. To avoid the confusion moving forward, we recommend using
requestIdleCallback
,setTimeout
, or a ref callback on the root.So instead of this:
You can do this:
See codesandbox.
Why ship both?
We’re shipping the legacy API in React 18 for two reasons:
Beta Was this translation helpful? Give feedback.
All reactions