如何使用多版本的React
在开发过程中使用联邦模块功能,使用其他项目的React组件,会出现 Minified React error #321; 错误。这是由于多个版本的React导致的。
在React@17中,事件系统进行了更改。这可以让我们使用React的多版本,解决多个版本的React导致的错误。
导出组件出口
我们创建一个函数,来包裹我们需要导出的组件出口。
import type { FunctionComponent, ComponentClass } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; interface CreateLegacyRoot { render(props: any): void; unmount(): void; } type LegacyReturn = (container: HTMLElement) => CreateLegacyRoot; /** * 创建一个createLegacyRoot函数,保证组件能够兼容多个react版本 * @param { FunctionComponent | ComponentClass } Component: 组件 */ function legacy(Component: FunctionComponent | ComponentClass): LegacyReturn { return function createLegacyRoot(container: HTMLElement): CreateLegacyRoot { return { render(props: any): void { render(<Component { ...props } />, container); }, unmount(): void { unmountComponentAtNode(container); } }; }; } export default legacy;
然后导出一个方法,供其他位置调用。
export const createLegacyRoot = legacy(Component);
在其他项目调用方法
我们创建一个Loader函数,来加载导出的方法。
import { useRef, useEffect } from 'react'; import PropTypes from 'prop-types'; /** * 加载联邦模块 * @param { Function } props.loader: 加载的联邦模块 * @param { object } props.moduleProps */ function Loader(props) { const { loader, moduleProps } = props; const containerRef = useRef(), // dom,ReactDOM.render渲染的节点 rootRef = useRef(); // 保存root对象 // 加载并渲染模块 async function loadModule() { const { createLegacyRoot } = await loader(); rootRef.current = createLegacyRoot(containerRef.current); rootRef.current.render(moduleProps); } useEffect(function() { loadModule(); return function() { rootRef.current.unmount(); }; }, [loader, moduleProps]); return <div ref={ containerRef } />; } Loader.propTypes = { loader: PropTypes.func, moduleProps: PropTypes.object }; export default Loader;
然后加载组件并调用。
function App(props) { function handleClick(event) { alert('你点击了按钮。'); } return ( <div> <Loader loader={ () => import('project/module') } moduleProps={{ onClick: handleClick }} /> </div> ); }