前言
接着上一篇,上一篇讲了简单的qiankun实例,以及vue子应用的使用, 那么, 这一篇就实践一下react子应用的使用,子应用独立运行, 及子应用内路由跳转,一个步骤一个步骤实践
一.准备
npm i create-react-app -g
// 先安装脚手架
2.创建项目
首先在主应用同级目录下, 创建react的子应用, 这里名字设置为qiankun-testchild2, 使用上方脚手架搭建
create-react-app qiankun-testchild2
3. 改造子应用, 上一篇中讲到了子应用的改造, 那么这个react项目也是类似的,
首先 , 将public中index.html中的根id改掉
4.然后就是修改webpack配置, 这里的话, react中, 在不ejec的情况下, 需要安装两个依赖来进行修改配置
npm install react-app-rewired customize-cra --save-dev
5.安装好了之后, 在子应用的根目录下, 创建一个config-overrides.js的文件, 这个文件用于配置webpack的基本配置, 基本配置的要点, 在上一个vue子应用中说过了, 这里就不细说了, 直接上代码
module.exports = {
webpack: (config) => {
config.output.library = 'qiankun-testchild2'
config.output.libraryTarget = 'umd'
config.output.publicPath = 'http://localhost:9726'
return config
},
devServer: (configFunction) => {
// devServer要求返回一个函数
return function(proxy, allowedHost) {
const config = configFunction(proxy, allowedHost)
// 以下端口修改直接写在.env文件中,默认会去这个文件中拿环境变量
config.headers = {
'Access-Control-Allow-Origin': '*'
}
return config
}
}
}
6.再创建一个.env文件, 这个文件默认读取端口, 那么在这个文件中, 写好端口定义就行了,
PORT=9726
WDS_SOCKET_PORT=9726
7.写好webpack配置之后, 需要修改一下package.json, 因为使用了 react-app-rewired
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom"
},
8. 那么这些都配置好了之后, 就需要改造index.js了, 同样是需要shared文件夹,去保持获取主应用数据通信, 然后子应用的qinakun三个生命周期. 以及区分独立运行和子应用运行的判断, 直接上代码
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import actions from "../src/shared/action";
// import reportWebVitals from './reportWebVitals';
function render(props={}) {
if (props) {
// 注入 actions 实例
actions.setActions(props);
}
const { container } = props;
ReactDOM.render(<App />, container ? container.querySelector('#app3') : document.getElementById('app3'));
}
if (window.__POWERED_BY_QIANKUN__) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
if(!window.__POWERED_BY_QIANKUN__) {
console.log('123123')
// 子应用独立执行时
render()
}
export async function bootstrap(props) {
console.log('react app bootstraped');
}
export async function mount(props) {
render(props)
}
export async function unmount(props) {
ReactDOM.unmountComponentAtNode(props.container ? props.container.querySelector('#app3') : document.getElementById('app3'));
}
9. index.js中用到了action, 跟vue子应用一样, 可以直接把文件夹复制过来. 当然, 如果后续全局交互数据的类型不同的话, 内部还是需要单独设置某些修改获取属性方法的.
10. index.js修改完成后, 就需要修改app.js了, 那么, 在app.js中,同样在DOM完成阶段: componentDidMount, 去共享数据, 修改state的值,(react当中, state值不能直接修改, 需要使用this.setState),
关于react的使用及语法, 可以参见之前写的一篇:juejin.cn/post/684490…
代码如下:
import './App.css';
import actions from "./shared/action";
import React, { Component } from 'react';
class App extends Component {
state = {
msg: ''
}
componentDidMount () {
// 這裡共享數據, 加上判斷, 便於獨立啟動
if (window.__POWERED_BY_QIANKUN__) {
actions.onGlobalStateChange(state => {
const { token } = state;
// 未登录 - 返回主页
this.setState({
msg: token
})
}, true);
}
}
render () {
return (
<div className="App">
<header className="App-header">
購物車系列 {this.state.msg}
</header>
</div>
);
}
}
export default App;
11. 在componentDidMount 阶段加上判断的原因就是, 如果它是独立启动,那么就不会注册actions, 就避免了独立启动时找不到actions的问题,
12. 然后呢, 子应用弄好之后, 就需要到主应用去注册一下, 就是在主应用的main.js中apps数组中,添加上这个子应用就好了, 之后的子应用也是一样的,基本的东西就不再做解释了.
let apps = [
{
name: "qiankun-testchild1",
entry: '//localhost:9725',
container: "#subapp",
activeRule: "/qiankun-testchild1",
props: {
name: "kuitos"
}
},
{
name: "qiankun-testchild2",
entry: '//localhost:9726',
container: "#subapp",
activeRule: "/qiankun-testchild2",
props: {
name: "kuitos"
}
}
]
13. 然后可以启动看下组合效果和单独启动效果.
14. 那么到这里, 基本上就简单的集成好了vue和react项目了, 独立运行呢, 刚才也做到了, 就是把注册action的过程做一个判断, 可以理解为跟主应用有关联的数据部分做个独立运行的场景判断. 那么接下来就实践一下, 如何在子应用中进行路由跳转
1. 子应用内路由跳转,以vue子应用为例
子应用内的路由跳转, 依旧可以使用router的方式进行跳转,先创建router-view容器
然后, 添加两个子页面
再在router文件中注册访问路径, 这里需要处理一下重复跳转的问题
可以看到上图中, 三个红框部分, 第一个红框处理重复跳转的问题, 第二个红框注册路由, 第三个红框中, base特别注意, 可以改成当前子应用路由,那么上面的路由就不用加子应用的路由了,但是子应用间跳转会出现base路径的问题, 好, 下面运行图.
2. 子应用间跳转,
那么这个就用react子应用跳转到vue子应用, 首先, 需要在app中包裹BrowserRouter
然后, 在router4以上中, 要使用history跳转, 需要createBrowserHistory, 用法如下, history不用安装
import './App.css';
import actions from "./shared/action";
import { withRouter } from "react-router-dom";
import {createBrowserHistory} from "history";
import React, { Component } from 'react';
class App extends Component {
state = {
msg: ''
}
componentDidMount () {
// 這裡共享數據, 加上判斷, 便於獨立啟動
if (window.__POWERED_BY_QIANKUN__) {
actions.onGlobalStateChange(state => {
const { token } = state;
// 未登录 - 返回主页
this.setState({
msg: token
})
}, true);
}
}
toChild1() {
let history = createBrowserHistory()
// console.log(this.history)
history.push('/qiankun-testchild1/test1')
// history.pushState(null, '/qiankun-testchild1/test1', '/qiankun-testchild1/test1');
}
render () {
return (
<div className="App">
<header className="App-header">
購物車系列 {this.state.msg}
<button onClick={this.toChild1}>點擊我跳轉</button>
</header>
</div>
);
}
}
export default withRouter(App);
好了, 现在可以尝试下子应用间的跳转, 效果如下图
好, 可以看出, 路径正确了, 但是没有加载出来下一级, 那么, 修改一下,vue子应用的生命周期,这个是因为没有注销
把注释替换一下
好了, 再来看下效果
vue内部跳转, 正常 从vue跳转到react, 正常 从react跳转到vue, 正常 再次点击标签跳转在线商品主页, 正常
15. 好了, 以上的话, 就基本创建了两个集成子应用, 并且把子应用内和子应用间跳转的问题解决了. 下一篇, 会把这两个子应用内容完善掉, 因为更多的子应用添加集成的步骤都是类似的, 所以,之后的子应用就不作解释了. 主要分析实践应用通信这一块.
16, 最后附上项目链接: github.com/hejiyun/qia…
结语
欲上琼楼邀满月,回首故园已是秋. 各位, 望归来依旧是少年!