Skip to content

Commit

Permalink
Require createRoot/hydrateRoot from 'react-dom/client' under react-do…
Browse files Browse the repository at this point in the history
…m 18+

Fixes #1441
  • Loading branch information
alexeyr committed Jun 23, 2022
1 parent 3c7751c commit 68019ae
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 101 deletions.
7 changes: 2 additions & 5 deletions node_package/src/ReactOnRails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ import type {
AuthenticityHeaders,
StoreGenerator
} from './types/index';
import reactHydrate from './reactHydrate';
import reactRender from './reactRender';
import reactHydrateOrRender from './reactHydrateOrRender';

/* eslint-disable @typescript-eslint/no-explicit-any */
type Store = any;
Expand Down Expand Up @@ -188,9 +187,7 @@ ctx.ReactOnRails = {
const componentObj = ComponentRegistry.get(name);
const reactElement = createReactOutput({ componentObj, props, domNodeId });

const render = hydrate ? reactHydrate : reactRender;
// eslint-disable-next-line react/no-render-return-value
return render(document.getElementById(domNodeId) as Element, reactElement as ReactElement);
return reactHydrateOrRender(hydrate, document.getElementById(domNodeId) as Element, reactElement as ReactElement);
},

/**
Expand Down
7 changes: 2 additions & 5 deletions node_package/src/clientStartup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import type {

import createReactOutput from './createReactOutput';
import {isServerRenderHash} from './isServerRenderResult';
import reactHydrate from './reactHydrate';
import reactRender from './reactRender';
import reactHydrateOrRender from './reactHydrateOrRender';

declare global {
interface Window {
Expand Down Expand Up @@ -168,10 +167,8 @@ function render(el: Element, railsContext: RailsContext): void {
throw new Error(`\
You returned a server side type of react-router error: ${JSON.stringify(reactElementOrRouterResult)}
You should return a React.Component always for the client side entry point.`);
} else if (shouldHydrate) {
reactHydrate(domNode, reactElementOrRouterResult as ReactElement);
} else {
reactRender(domNode, reactElementOrRouterResult as ReactElement);
reactHydrateOrRender(shouldHydrate, domNode, reactElementOrRouterResult as ReactElement);
}
}
} catch (e: any) {
Expand Down
12 changes: 0 additions & 12 deletions node_package/src/reactHydrate.ts

This file was deleted.

41 changes: 41 additions & 0 deletions node_package/src/reactHydrateOrRender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { ReactElement, Component } from 'react';
import ReactDOM from 'react-dom';

type HydrateOrRenderReturnType = void | Element | Component;
type HydrateOrRenderType = (domNode: Element, reactElement: ReactElement) => HydrateOrRenderReturnType;
const supportsReactCreateRoot = parseInt(ReactDOM.version.split('.')[0], 10) >= 18;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
let reactDomClient: any;
if (supportsReactCreateRoot) {
if (require.context) {
// we are in a Webpack environment (and in a node-modules directory of another project)
// See https://webpack.js.org/guides/dependency-management/#context-module-api
const reactDomContext = require.context('../react-dom/', false, /^client\.js$/);
reactDomClient = reactDomContext('../react-dom/client.js');
} else {
// we want a dynamic require here so that webpack doesn't rewrite it
const reactDomClientName = 'react-dom/client';
// eslint-disable-next-line global-require,import/no-dynamic-require
reactDomClient = require(reactDomClientName);
}
}

export const reactHydrate: HydrateOrRenderType = supportsReactCreateRoot ?
reactDomClient.hydrateRoot :
(domNode, reactElement) => ReactDOM.hydrate(reactElement, domNode);

export function reactRender(domNode: Element, reactElement: ReactElement): HydrateOrRenderReturnType {
if (supportsReactCreateRoot) {
const root = reactDomClient.createRoot(domNode);
root.render(reactElement);
return root;
}

// eslint-disable-next-line react/no-render-return-value
return ReactDOM.render(reactElement, domNode);
}

export default function reactHydrateOrRender(shouldHydrate: boolean, domNode: Element, reactElement: ReactElement): HydrateOrRenderReturnType {
return shouldHydrate ? reactHydrate(domNode, reactElement) : reactRender(domNode, reactElement);
}
15 changes: 0 additions & 15 deletions node_package/src/reactRender.ts

This file was deleted.

8 changes: 0 additions & 8 deletions node_package/src/supportsReactCreateRoot.ts

This file was deleted.

44 changes: 0 additions & 44 deletions node_package/tests/supportsReactCreateRoot.test.js

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
"@babel/preset-react": "^7.12.10",
"@babel/types": "^7.12.10",
"@types/jest": "^26.0.18",
"@types/node": "^14.14.11",
"@types/react": "^16.9.23",
"@types/react-dom": "^16.9.5",
"@types/turbolinks": "^5.2.0",
"@types/webpack-env": "^1.17.0",
"@typescript-eslint/eslint-plugin": "^4.10.0",
"@typescript-eslint/parser": "^4.10.0",
"babelify": "^10.0.0",
Expand Down
11 changes: 5 additions & 6 deletions spec/dummy/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6349,7 +6349,7 @@ react-is@^16.7.0:
integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==

"react-on-rails@file:.yalc/react-on-rails":
version "13.0.1"
version "13.0.2"
dependencies:
"@babel/runtime-corejs3" "^7.12.5"
concurrently "^5.1.0"
Expand Down Expand Up @@ -6983,11 +6983,10 @@ sha.js@^2.4.0, sha.js@^2.4.8:
inherits "^2.0.1"
safe-buffer "^5.0.1"

[email protected]:
name shakapacker
version "6.4.0"
resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-6.4.0.tgz#f49ad8bb51eb1a151b190b588ad467c6e6f62e69"
integrity sha512-bxxi7Lla3n2fnFjxVv6BtD2vcTEZIm2eb29WkJqZBmpFVT9tnwbd3XQISD9eOst6kTEJu2ruUp7dGvuEjpxwkg==
shakapacker@^6.4.0:
version "6.4.1"
resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-6.4.1.tgz#4c3662c63acf54ecd7847f97ceb88ee1a23bfa2a"
integrity sha512-yCGqDVNP5Dz4W8wAl53M/zG6/xpvAaFItPVVlDuHyq3xCzHD2MYEBvmITNgBvvl2WU34OPcEIeVrXOWcl/MCMQ==
dependencies:
glob "^7.2.0"
js-yaml "^4.1.0"
Expand Down
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1594,11 +1594,6 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.35.tgz#42c953a4e2b18ab931f72477e7012172f4ffa313"
integrity sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==

"@types/node@^14.14.11":
version "14.14.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.11.tgz#fc25a4248a5e8d0837019b1d170146d07334abe0"
integrity sha512-BJ97wAUuU3NUiUCp44xzUFquQEvnk1wu7q4CMEUYKJWjdkr0YWYDsm4RFtAvxYsNjLsKcrFt6RvK8r+mnzMbEQ==

"@types/normalize-package-data@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
Expand Down Expand Up @@ -1639,6 +1634,11 @@
resolved "https://registry.yarnpkg.com/@types/turbolinks/-/turbolinks-5.2.0.tgz#cdfd3691143ea2f452113c2a06bd12d9a88b25d6"
integrity sha512-xEgHb25lj23EaUlsU3Y4KlFH7elhlYINGSnqyn/8zmcMnenY4Idyjk/x9kw1kOoOToY3de9fD8NSwRzNc6f5nw==

"@types/webpack-env@^1.17.0":
version "1.17.0"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.17.0.tgz#f99ce359f1bfd87da90cc4a57cab0a18f34a48d0"
integrity sha512-eHSaNYEyxRA5IAG0Ym/yCyf86niZUIF/TpWKofQI/CVfh5HsMEUyfE2kwFxha4ow0s5g0LfISQxpDKjbRDrizw==

"@types/yargs-parser@*":
version "20.2.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9"
Expand Down

0 comments on commit 68019ae

Please sign in to comment.