主应用vue3 + vite
子应用1: Vue3 + vite github.com/huzhushan/v...
子应用2: Create React App + Webpack
通过vuex/pinia实现通信
第一步:在主应用中创建一个store
src/store/index.ts
js
const personModule = {
state: {
id: 0,
name: '',
age: 0
},
mutations: {
setId(state: Object, id: number) {
state.id = id
},
setName(state: Object, name: string) {
state.name = name
},
setAge(state: Object, age: number) {
state.age = age
}
},
actions: {
setId(context: Object, id: number) {
context.commit('setId', id)
},
setName(context: Object, name: string) {
context.commit('setName', name)
},
setAge(context: Object, age: number) {
context.commit('setAge', age)
}
}
}
export default new Vuex.Store({
state: {
},
getters: {},
mutations: {
},
actions: {
},
modules: {
personModule
}
})
第二步:在main.js文件中引入这个store,并通过RegistrableApp
的props
传给子应用
js
import store from './store/index'
import { registerMicroApps, start, initGlobalState } from 'qiankun'
registerMicroApps([
{
name: 'vue3-element-admin',
entry: '//localhost:3001',
container: '#container',
activeRule: '/#/vue3-element-admin',
props: {
store,
}
}
],
)
第三步:在子应用的main.js
文件中接收这个store
,并通过createApp()
的第二个参数props
,将主应用的这个store
传递到子应用的根组件App.vue
中。
js
renderWithQiankun({
mount(props) {
appMount(props);
},
//、、、
})
function appMount(props) {
app = createApp(App, {
parentStore: props.store
})
}
第四步:在子应用的根组件App.vue
文件中,通过props
接收这个store
,并通过provite()
将这个store
注入到所有子组件中
js
export default defineComponent({
props: {
parentStore: Object
},
setup(props) {
const { lang } = useLang()
provide('parentStore', props.parentStore)
//、、、
}
})
第五步:在需要的子组件中,通过inject()
接收这个store
,并根据需要操作这个store
js
<script setup>
import { onMounted, onUnmounted , onActivated, onDeactivated, inject } from 'vue';
const parentStore = inject('parentStore')
const personModule = parentStore.state.personModule
const changeParentStore = () => {
parentStore?.dispatch('setId', '11')
parentStore?.dispatch('setName', 'lily')
parentStore?.dispatch('setAge', 18)
}
</script>
通过vuex创建的store也可以在react子应用中使用
子项目Create-React-App + webpack
第一步,在入口处接收store, 然后传递给根组件
js
let root;
function render(props) {
const rootProps = {
parentStore: props.store
}
root = ReactDOM.createRoot(props?.container ? props.container.querySelector('#root') : document.querySelector('#root'));
root.render(
<React.StrictMode>
<App { ...rootProps } /> //将store传递给根组件
</React.StrictMode>
);
}
export async function mount(props) {
render(props)
}
第二步:在根组件或其他子组件中使用store
js
function App(props) {
const parentStore = props?.parentStore
const personModule = props?.parentStore?.state?.personModule
const changeParentStore = () => {
parentStore.commit('setId', 11)
parentStore.commit('setName', 'Lucy')
parentStore.commit('setAge', 18)
forceRemount()
}
const [key, setKey] = useState(0);
// 当需要强制重新渲染时,调用这个函数
const forceRemount = () => {
setKey(currentKey => currentKey + 1);
};
return (
<div>
<div>展示主应用vue传过来的store:{personModule?.id}</div>
<div>展示主应用vue传过来的store:{personModule?.name}</div>
<div>展示主应用vue传过来的store:{personModule?.age}</div>
<div>
<Button type='primary' onClick={changeParentStore}>
修改主应用的store
</Button>
</div>
</div>
)
通过EventBus实现通信
第一步:在主应用中创建一个EventBus
src/eventBus/index.ts
js
import mitt from 'mitt'
const eventBus = mitt()
export default eventBus;
第二步:在main.js
文件中引入这个eventBus
,并通过RegistrableApp
的props
传给子应用(类似Vuex)
js
import eventBus from './eventBus/index'
registerMicroApps([
{
name: 'vue3-element-admin',
entry: '//localhost:3001',
container: '#container',
activeRule: '/#/vue3-element-admin',
props: {
store,
eventBus
}
}
],
)
第三步:在子应用的main.js
文件中接收这个store
,并通过createApp()
的第二个参数props
,将主应用的这个eventBus
传递到子应用的根组件App.vue
中。
js
renderWithQiankun({
mount(props) {
appMount(props);
},
})
let app;
function appMount(props) {
app = createApp(App, {
parentStore: props?.store,
parentEventBus: props?.eventBus
})
//...
}
第四步:在子应用的根组件App.vue
文件中,通过props
接收这个eventBus
,并通过provite()
将这个eventBus
注入到所有子组件中
js
setup(props) {
provide('parentEventBus', props.parentEventBus)
}
第五步:在主应用的App.vue文件中,引入eventBus,订阅一个setUserName事件
js
import eventBus from "./eventBus/index"
const userName : any = ref('')
eventBus.on('setUserName', (name) => {
userName.value = name;
})
第六步:在子应用需要的子组件中,触发setUserName事件
js
const userName = ref('')
const parentEventBus = inject('parentEventBus')
const changeUserName = () => {
parentEventBus?.emit('setUserName', userName.value)
}
注意:如果订阅事件的组件销毁了,则通信失败
使用 qiankun initGlobalState
第一步: 在主应用中创建一个全局状态
actions.setGlobalState()传入的对象,与原对象存在相同的key则修改value,原对象不存在相同的key则直接新增。
- 微应用中只能修改已存在的一级属性
js
import { registerMicroApps, start, initGlobalState } from 'qiankun'
const state = {
a: 2,
b: 2
}
const actions : MicroAppStateActions = initGlobalState(state);
actions.onGlobalStateChange((state, prev) => {
console.log('主应用监听GlobalState:', state, prev)
})
actions.setGlobalState({
c: 3, // 该属性会附加到state中
});
第二步:子应用直接使用props
上的onGlobalStateChange
和setGlobalState
- 子应用上新增的key不生效
js
props.onGlobalStateChange((state, prev) => {
// state: 变更后的状态; prev 变更前的状态
console.log('子应用监听GlobalState:', state, prev);
});
props.setGlobalState({
a: 11
})
props.setGlobalState({
b: 22
})
props.setGlobalState({
d: 4, // 新增的id,不会加到state上。
});
props.setGlobalState({
c: 33,
});
综上所述,个人觉得使用Vuex/pinia实现应用间通信应该是最好的方式。