Skip to content

Commit 0cdd4ad

Browse files
authored
feat: Suppot react v18 (#214)
1 parent 0af401a commit 0cdd4ad

File tree

4 files changed

+63
-12
lines changed

4 files changed

+63
-12
lines changed

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@
5252
"@kkt/raw-modules": "~7.1.1",
5353
"@kkt/scope-plugin-options": "~7.1.1",
5454
"@types/babel__standalone": "~7.1.4",
55-
"@types/react": "~17.0.39",
56-
"@types/react-dom": "~17.0.13",
55+
"@types/react": "18.0.5",
56+
"@types/react-dom": "18.0.1",
5757
"@types/react-test-renderer": "~17.0.1",
5858
"@uiw/react-github-corners": "~1.5.3",
5959
"@uiw/react-markdown-preview": "~3.5.1",
@@ -63,8 +63,8 @@
6363
"kkt": "~7.1.5",
6464
"lint-staged": "~12.3.5",
6565
"prettier": "~2.5.1",
66-
"react": "~17.0.2",
67-
"react-dom": "~17.0.2",
66+
"react": "18.0.0",
67+
"react-dom": "18.0.0",
6868
"react-test-renderer": "~17.0.2",
6969
"source-map-explorer": "~2.5.2",
7070
"tsbb": "~3.7.2",
@@ -101,4 +101,4 @@
101101
"last 1 safari version"
102102
]
103103
}
104-
}
104+
}

src/useCodePreview.ts

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import React, { useEffect, useRef } from 'react';
2+
// @ts-ignore
3+
import ReactDOMClient from 'react-dom/client';
24
import ReactDOM from 'react-dom';
35
import { useState } from 'react';
46
import { babelTransform } from './transform';
@@ -14,13 +16,51 @@ export function useCodePreview(props: CodePreviewProps) {
1416
const [copied, setCopied] = useState(false);
1517
const [code, setCode] = useState(props.code || '');
1618

19+
/** 通过缓存的方式 解决 react v18 中 的报错 ***/
20+
// @ts-ignore
21+
const cachesRef = React.useRef(new Map<string, ReactDOMClient.Root>([]));
22+
const ReactDOMRender = (_ReactDOM: typeof ReactDOMClient) => {
23+
return {
24+
createRoot: (id: string) => {
25+
return {
26+
render: (render: React.ReactChild | Iterable<React.ReactNode>) => {
27+
const caches = cachesRef.current;
28+
let root = caches.get(id);
29+
// 存在则不需要重新创建直接进行render操作
30+
if (root) {
31+
root.render(render);
32+
} else {
33+
// @ts-ignore
34+
root = _ReactDOM.createRoot(document.getElementById(id)!);
35+
root.render(render);
36+
// 缓存,解决控制台报 ReactDOMClient.createRoot 问题
37+
caches.set(id, root);
38+
}
39+
cachesRef.current = caches;
40+
},
41+
};
42+
},
43+
};
44+
};
45+
/** ------------------------ ***/
46+
1747
const executeCode = (str: string) => {
18-
const { React: _React, ReactDOM: _ReactDOM, ...otherDeps } = props.dependencies || {};
48+
const {
49+
React: _React,
50+
ReactDOM: _ReactDOM,
51+
ReactDOMClient: _ReactDOMClient,
52+
...otherDeps
53+
} = props.dependencies || {};
54+
const V18ReactDOM = _ReactDOMClient || ReactDOMClient || _ReactDOM || ReactDOM;
55+
// 判断是否是 react v18版本
56+
const isV18 = Reflect.has(V18ReactDOM || {}, 'createRoot');
57+
const NewReactDOM = isV18 ? ReactDOMRender(V18ReactDOM) : V18ReactDOM;
58+
1959
try {
2060
const deps = {
2161
React: _React || React,
22-
ReactDOM: _ReactDOM || ReactDOM,
2362
...otherDeps,
63+
ReactDOM: NewReactDOM,
2464
} as any;
2565
// const args = ['context', 'React', 'ReactDOM', 'Component'];
2666
const args = [];
@@ -30,7 +70,17 @@ export function useCodePreview(props: CodePreviewProps) {
3070
args.push(key);
3171
argv.push(deps[key]);
3272
}
33-
str = str.replace('_mount_', `document.getElementById('${playerId.current}')`);
73+
74+
if (isV18) {
75+
// react < v18 中写法替换
76+
str = str.replace('ReactDOM.render', `ReactDOM.createRoot("${playerId.current}").render`);
77+
// react v18 中写法替换
78+
str = str.replace(`ReactDOMClient.createRoot(_mount_)`, `ReactDOM.createRoot("${playerId.current}")`);
79+
str = str.replace('_mount_', ``);
80+
} else {
81+
str = str.replace('_mount_', `document.getElementById('${playerId.current}')`);
82+
}
83+
3484
const input = `${str}`;
3585
const { code } = babelTransform(input);
3686
args.push(code || '');

website/Example.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import CodePreview from '../';
33
import { Switch } from 'uiw';
44
import * as UIW from 'uiw';
55

6-
const defaultCode = `import ReactDOM from 'react-dom';
6+
const defaultCode = `
77
import { Button, Divider, Icon } from 'uiw';
8+
import ReactDOMClient from 'react-dom/client';
89
910
ReactDOM.render(
1011
<div>

website/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React from 'react';
2-
import ReactDOM from 'react-dom';
2+
// import ReactDOM from 'react-dom';
3+
import ReactDOM from 'react-dom/client';
34
import '@uiw/reset.css/reset.less';
45
import App from './App';
56

6-
ReactDOM.render(
7+
ReactDOM.createRoot(document.getElementById('root')).render(
78
<React.StrictMode>
89
<App />
910
</React.StrictMode>,
10-
document.getElementById('root'),
1111
);

0 commit comments

Comments
 (0)