React主应用动态加载子应用组件并传递参数可行性咨询
当然可行!给动态加载的React组件传递参数的方案
兄弟,你的这个微前端思路完全没问题,而且给App1传递参数(比如目标元素ID)绝对可行!我来给你拆解下怎么调整现有代码实现这个需求,还能顺便优化下当前用eval加载的方式(毕竟eval在生产环境有安全和性能隐患)。
一、调整App1的代码,让它支持接收参数
现在你的App1应该是直接绑定到固定元素ID对吧?我们可以把它改成一个可调用的函数,让它接收外部传入的参数:
- 打开App1的
src/index.js(或者你用来导出组件的入口文件),把原来直接渲染的代码改成一个函数:
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; // 把渲染逻辑封装成函数,接收目标元素ID作为参数 export function renderApp1(targetElementId) { const root = ReactDOM.createRoot(document.getElementById(targetElementId)); root.render( <React.StrictMode> <App /> </React.StrictMode> ); } // 保留原来的逻辑,方便单独开发调试 if (process.env.NODE_ENV === 'development') { renderApp1('root'); }
- 然后修改App1的打包配置,让它输出一个UMD模块(这样主应用可以通过全局变量或者模块的方式访问到
renderApp1函数)。如果你用的是create-react-app,需要安装react-app-rewired和customize-cra来修改webpack配置:
- 安装依赖:
npm install react-app-rewired customize-cra --save-dev - 在项目根目录创建
config-overrides.js:
const { override, setWebpackConfig } = require('customize-cra'); module.exports = override( setWebpackConfig({ output: { library: 'App1', // 全局变量名 libraryTarget: 'umd', umdNamedDefine: true, }, }) );
- 修改
package.json的启动脚本:
"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-scripts eject" }
- 执行
npm run build,打包后的static/js/main.xxx.js就会暴露全局变量App1,里面包含renderApp1函数。
二、主应用修改加载逻辑,传递参数
把原来用eval的方式换成更安全的动态创建script标签的方式,然后在脚本加载完成后调用renderApp1并传递目标元素ID:
// 主应用里的加载App1函数 const loadApp1 = (targetElementId) => { return new Promise((resolve, reject) => { // 检查是否已经加载过App1 if (window.App1) { window.App1.renderApp1(targetElementId); resolve(); return; } // 创建script标签加载App1的打包JS const script = document.createElement('script'); script.src = 'http://Server1的地址/static/js/main.xxx.js'; // 替换成你的Server1实际地址 script.onload = () => { // 加载完成后调用renderApp1,传入目标元素ID window.App1.renderApp1(targetElementId); resolve(); }; script.onerror = reject; document.body.appendChild(script); }); }; // 调用示例:点击按钮加载App1到指定元素 <button onClick={() => loadApp1('app1-container')}>加载App1</button> // 主应用里提前准备好目标元素 <div id="app1-container"></div>
三、进阶:传递更多自定义参数
如果需要传递除了元素ID之外的其他参数(比如用户信息、配置项),直接扩展renderApp1函数就行:
// App1的render函数 export function renderApp1(targetElementId, props = {}) { const root = ReactDOM.createRoot(document.getElementById(targetElementId)); root.render( <React.StrictMode> <App userInfo={props.userInfo} config={props.config} /> </React.StrictMode> ); } // 主应用调用时传递更多参数 loadApp1('app1-container', { userInfo: { id: 1, name: '张三' }, config: { theme: 'dark' } });
为什么不推荐用eval?
eval会执行任意字符串,存在XSS安全风险,而且浏览器无法对eval里的代码进行优化,性能不如直接加载脚本或者使用模块加载器。如果一定要用动态加载代码的方式,也可以用new Function()替代,比eval安全一点,但还是不如动态script标签靠谱。
内容的提问来源于stack exchange,提问作者Tudor Rogojanu
相关产品推荐
相关产品推荐

