Calling ReactDOM.render() many many times is slow

walkerburgin
创建于
2018-04-26 18:42:43

Do you want to request a feature or report a bug?

Bug (?)

What is the current behavior?

Calling ReactDOM.render() many many times seems to have meaningfully worse performance than rendering many elements within a single React root.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:

// Edited to add dev/production builds

(These examples are obviously pretty contrived)

What is the expected behavior?

In a perfect world there wouldn't be such a large performance discrepancy between these two approaches.

For context, I'm working with a frontend plugin framework and trying not to expose React (which should ideally be an implementation detail) as part of the plugin interface.

An interface like this requires both the host and the plugin to be implemented with React and to share the same instance of React... but is fast and convenient when they do:

render(props: T): JSX.Element;

An interface like this treats React as an implementation detail, but is less convenient and (more importantly) incurs the above performance problem:

render(props:T, element: HTMLElement): void; 
unmount(element: HTMLElement): void;

I imagine this use case isn't a high priority for React/ReactDOM, but I'd love to understand a bit better what it is that really causes the performance difference and whether it's likely to ever change.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

  • Seems to impact both React 15 & 16 similarly
  • I don't think it's browser dependent
8条回答
gaearon
回复于
2018-04-26 18:44:42
#1

I haven't looked yet but my first question is whether the difference is significant in production mode. The fiddles you're showing are running in development mode.

walkerburgin
回复于
2018-04-26 18:55:08
#2

From what I've seen the difference is similar in production mode, you just start to really see it at higher element counts.

I've played around a little trying to understand how different usage patters impact it. Frequency of updates which require a DOM change, for example, or updates vs lots of mounting & unmounting components. So far I haven't really isolated anything particularly useful.

miraage
回复于
2018-04-27 16:04:10
#3

Calling ReactDOM.render() many many times seems to have meaningfully worse performance than rendering many elements within a single React root.

Not sure if I understand React under the hood correctly, but let's think about it.
When you call ReactDOM.render you need to destroy/replace contents of the target node.
Meanwhile, if you use a single root then Virtual DOM will take care of DOM operations.

We know that DOM mutations are pretty (very?) expensive.

So.. I wouldn't be surprised.

walkerburgin
回复于
2018-04-27 17:11:55
#4

When you call ReactDOM.render you need to destroy/replace contents of the target node.

Is this actually true? My understanding is that that's actually not the case. With the repro examples what's actually being rendered is the same in either case way so the number of DOM mutations don't have to be wildly different.

That said, I can understand some overhead for each root and how many roots might make batching / scheduling worse -- I just don't know enough about the guts of React's implementation to fully explain it.

gaearon
回复于
2018-04-27 18:04:28
#5

There shouldn't be a difference in DOM mutations.

gaearon
回复于
2018-08-07 01:07:05
#6

I fixed the biggest difference that jumped out at me in #13335.

There's some other differences in DEV (e.g. in React 15 we don't emit perf measurements by default, but in React 16 we do, and they have a fixed cost). But in production it should get better in the next patch release that includes #13335 (presumably 16.4.3 or 16.5.0).

Note in general though we don't recommend using many roots when it's avoidable. It's supported of course but it makes React's job more difficult. As far as I can see, if you use createPortal() in the render method instead of having many ReactDOM.render() calls, the performance significantly improves even in the version of React that's currently published. In general, I think your goal of abstracting away React can make it more difficult for you to benefit from React-specific optimizations like time slicing in the future — so that's another thing to consider.

Thanks for the repro case!

NE-SmallTown
回复于
2018-08-15 03:02:19
#7

@gaearon

if you use createPortal() in the render method instead of having many ReactDOM.render() calls

If so, why in the React tests we use calling the ReactNoop.render or ReactDOM.render many times, should we use other way to test such as setState in the root component?

gaearon
回复于
2018-08-15 10:15:50
#8

The difference is not significant enough to matter in tests.

当前位于第1页,总计8 条回复

推荐相似问题

Styles via className not reflected in print

Do you want to request a feature or report a bug? Not 100% sure, but might be a bug (or just something I'm not doing rig
讨论数 2
react
创建时间:2018-04-26 15:25:04

Conditional Rendering Such as JSX-Control-Statements

Do you want to request a feature or report a bug? Neither Conditional Rendering Components like JSX-Control-Statement ht
讨论数 4
react
创建时间:2018-04-26 15:03:46

Ref callback is not called before componentDidMount

Do you want to request a feature or report a bug? Bug What is the current behavior? ref callback is not executed before
讨论数 2
react
创建时间:2018-04-26 12:32:46

Allow to specify displayName for createContext() providers and consumers

Do you want to request a feature or report a bug? bug What is the current behavior? in React tree name of a Context must
讨论数 6
react
创建时间:2018-04-26 09:52:26

Size prop is not attached to the DOM

Do you want to request a feature or report a bug? Bug What is the current behavior? The size prop can only be a number a
讨论数 9
react
创建时间:2018-04-26 06:50:06

react-test-renderer.create does not work properly with forwardRef components

Do you want to request a feature or report a bug? Bug What is the current behavior? If you try to access the .root of a
讨论数 8
react
创建时间:2018-04-26 02:47:56

<textarea autoFocus/> seems to leak DOM nodes

Do you want to request a feature or report a bug? Report a bug What is the current behavior? React components with <text
讨论数 4
react
创建时间:2018-04-25 23:54:13

It's possible to do unlimited recursive rendering with an HOC

Do you want to request a feature or report a bug? I would consider it a feature 😈 What is the current behavior? React d
讨论数 4
react
创建时间:2018-04-25 21:13:28

Cloning the child of a context Consumer produces confusing warning and error

Do you want to request a feature or report a bug? this is a bug, or at least a request for more precise warnings and err
讨论数 5
react
创建时间:2018-04-25 17:30:19

Unexpected behavior when use React.forwardRef with React.createContext

Do you want to request a feature or report a bug? bug What is the current behavior? example: https://codesandbox.io/s/04
讨论数 3
react
创建时间:2018-04-25 14:16:43