@antv/s2-react
Version:
use S2 with react
119 lines • 4.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.forceClearContent = exports.reactUnmount = exports.reactRender = exports.isLegacyReactVersion = exports.S2_REACT_ROOT_SYMBOL_ID = void 0;
const tslib_1 = require("tslib");
/**
* 兼容 React 16/17/18/19 的挂载和卸载
*/
const react_1 = require("react");
const ReactDOM = tslib_1.__importStar(require("react-dom"));
exports.S2_REACT_ROOT_SYMBOL_ID = `__s2_react_root__`;
// 1. 避免直接解构 render,防止 React 19 报错
// 仅保留类型定义和必要的静态属性引用
const ReactDOMClone = Object.assign({}, ReactDOM);
let createRootFn;
// 2. 异步获取 createRoot
// 这是一个懒加载单例,只在第一次渲染时执行
function getCreateRoot() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (createRootFn) {
return createRootFn;
}
// 优先尝试 React 18 的同步入口 (如果有)
if (ReactDOMClone.createRoot) {
createRootFn = ReactDOMClone.createRoot;
return createRootFn;
}
// React 19+ 或 React 18 Client 模式
try {
const client = yield Promise.resolve().then(() => tslib_1.__importStar(require('react-dom/client')));
createRootFn = client.createRoot;
return createRootFn;
}
catch (e) {
throw new Error('[S2] React 18+ detected but failed to load createRoot. Please ensure react-dom is installed correctly.', { cause: e });
}
});
}
const isLegacyReactVersion = () => {
const mainVersion = Number((react_1.version || '').split('.')[0]);
return mainVersion < 18;
};
exports.isLegacyReactVersion = isLegacyReactVersion;
/**
* 由于兼容的关系, 没有从 "react-dom/client" 引入 createRoot, 会报 warning
* https://github.com/facebook/react/issues/24372
*/
function toggleWarning(skip) {
const { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED } = ReactDOMClone;
if (__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED &&
typeof __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED === 'object') {
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.usingClientEntryPoint =
skip;
}
}
// ========================== Render ==========================
function modernRender(node, container) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
toggleWarning(true);
let root = container[exports.S2_REACT_ROOT_SYMBOL_ID];
if (!root) {
// 异步等待 createRoot 加载完成
const createRoot = yield getCreateRoot();
root = createRoot(container);
container[exports.S2_REACT_ROOT_SYMBOL_ID] = root;
}
toggleWarning(false);
root.render(node);
return root;
});
}
function legacyRender(node, container) {
const reactRender = ReactDOMClone.render;
if (reactRender) {
reactRender(node, container);
}
else {
throw new Error('[S2] Failed to render. React 16/17 detected but ReactDOM.render is empty');
}
}
// 注意:这里变成了 async 函数
function reactRender(node, container) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (!(0, exports.isLegacyReactVersion)()) {
yield modernRender(node, container);
return;
}
legacyRender(node, container);
});
}
exports.reactRender = reactRender;
// ========================= Unmount ==========================
function modernUnmount(container) {
return Promise.resolve().then(() => {
var _a;
(_a = container === null || container === void 0 ? void 0 : container[exports.S2_REACT_ROOT_SYMBOL_ID]) === null || _a === void 0 ? void 0 : _a.unmount();
container === null || container === void 0 ? true : delete container[exports.S2_REACT_ROOT_SYMBOL_ID];
});
}
function legacyUnmount(container) {
const unmount = ReactDOMClone.unmountComponentAtNode;
if (container && unmount) {
unmount(container);
}
}
function reactUnmount(container) {
if (!(0, exports.isLegacyReactVersion)()) {
return modernUnmount(container);
}
return legacyUnmount(container);
}
exports.reactUnmount = reactUnmount;
function forceClearContent(container) {
if ((0, exports.isLegacyReactVersion)()) {
return legacyUnmount(container);
}
return modernRender(null, container);
}
exports.forceClearContent = forceClearContent;
//# sourceMappingURL=reactRender.js.map