Bogdan Gishka
Bogdan Gishka

Reputation: 484

How heavy in terms of performance the ReactDOM.render function at the start?

How bad it might be for performance to use multiple ReactDOM.render functions simultaneously? For example, up to 30+ ReactDOM.render calls.

I know it may sound strange. I'm currently working on a large web project that uses single ReactDOM.render function. One of the largest problems we've come up with was update to React 18. Since the project is pretty big and contains many legacy code there are many places where you can meet usage of legacy approaches that are not supported by the newest React version. I want to split one SPA on multiple independent subapplications (a.k.a. micro-frontends), but still use a single deployment build, have in-memory cache that can be shared across apps, keep SPA experience for users, etc. Yet, at the same time have the capability of gradual migration on a newer versions of React.

We've already managed to create a working proof of concept by refactoring two subapps. Currently the startup of every app looks somewhat like this:

// Subscribe on URL path change.
observer.on('changed', () => {
  if (window.location.path.includes(targetPath)) {
    ReactDOM.render(<App />, elementContainer);
  } else {
    ReactDOM.unmountComponentAtNode(elementContainer);
  }
});

As you can see we don't start React immediately, unless we enter the specific route. But ideally I would prefer if application's entry point looked like this:

const AppEntryPoint = () => {
  <Switch>
    <Route path="...">
      <App />
    </Route>
    <Route>{null}</Route>
  </Switch>
};

ReactDOM.render(<AppEntryPoint />, elementContainer);

And the question is: how bad it may be at the startup with 30+ entry points like this? Are there any other serious issues that I didn't notice?

Upvotes: 1

Views: 312

Answers (1)

adsy
adsy

Reputation: 11567

I've actually done similar to upgrade a legacy app and it was fine. I think the cumulative render time is very similar to having it in one tree.

However, I think you should think carefully before doing this. The release notes say:

Although the changes are usually small, you’ll still have the ability to make them at your own pace. The new rendering behavior in React 18 is only enabled in the parts of your app that use new features.

It honestly could be a small number of broken components caused by state update batching. Your approach is not necessarily incorrect depending on how bad the situation is; but you should only do it if it's really extreme. This will come at great cost, and also be hard to reverse. Maybe a small number of common components have a problem?

You could just wrap all your state updates in a flush and work backwards to remove them: https://blog.devgenius.io/understanding-automatic-batching-in-react-18-fb5b8fdf062d

I would usually encourage an incremental approach like yours, but you should think carefully about the cost of incremental vs big bang here because of how large the proposed changes would be with the incremental approach compared to the end state.

I'll also add, if you do do this, it might be better to add placeholder HTML elements to the pages -- then query these and load the React tree. Coupling to the URL will make moving code around harder. This worked for me in the past.

Upvotes: 1

Related Questions