当前位置: 首页 > news >正文

Vite+微前端Qiankun-状态管理

一、前言

在微前端架构中,状态管理是一个重要的课题。由于子应用是独立的,它们之间可能需要共享状态或通信。以下是基于qiankun微前端架构的状态管理方案,结合Vue 3Vite的实现。

二、状态管理方案

在微前端中,状态管理可以分为以下几种方式:

1. 主应用和子应用共享状态

  • 通过全局状态管理库(如 PiniaVuex)在主应用中管理全局状态,子应用通过主应用提供的接口访问或修改状态。
  • 使用 qiankuninitGlobalState 方法实现主应用和子应用之间的状态共享。

2. 子应用独立状态管理

  • 每个子应用使用自己的状态管理库(如 PiniaVuex),状态独立管理,不与其他子应用共享。

3. 事件通信

  • 使用 CustomEventEventBus 实现子应用之间的通信。

三、使用 qiankuninitGlobalState 实现状态共享

qiankun提供了initGlobalState方法,用于在主应用和子应用之间共享状态。

1. 主应用配置

在主应用中初始化全局状态。

// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { registerMicroApps, start, initGlobalState } from 'qiankun';

const app = createApp(App);
app.use(router);
app.mount('#app');

// 初始化全局状态
const initialState = {
  user: {
    name: 'Main App User',
  },
};

const actions = initGlobalState(initialState);

// 监听状态变化
actions.onGlobalStateChange((state, prevState) => {
  console.log('主应用:状态变化', state, prevState);
});

// 注册子应用
registerMicroApps([
  {
    name: 'subApp1',
    entry: '//localhost:7101',
    container: '#subapp-container',
    activeRule: '/subApp1',
  },
  {
    name: 'subApp2',
    entry: '//localhost:7102',
    container: '#subapp-container',
    activeRule: '/subApp2',
  },
]);

// 启动 qiankun
start();

2. 子应用配置

在子应用中获取和修改全局状态。

// subApp1/src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

let instance = null;

function render(props = {}) {
  const { container } = props;
  instance = createApp(App);
  instance.use(router);
  instance.mount(container ? container.querySelector('#app') : '#app');

  // 获取全局状态
  if (props.onGlobalStateChange && props.setGlobalState) {
    props.onGlobalStateChange((state, prevState) => {
      console.log('子应用1:状态变化', state, prevState);
    });

    // 修改全局状态
    props.setGlobalState({
      user: {
        name: 'SubApp1 User',
      },
    });
  }

    // 将 props 注入到 Vue 实例中
    instance.provide('MAIN_APP_PROPS', props);
}

if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

export async function bootstrap() {
  console.log('subApp1 bootstrap');
}

export async function mount(props) {
  console.log('subApp1 mount');
  render(props);
}

export async function unmount() {
  console.log('subApp1 unmount');
  instance.unmount();
  instance = null;
}

3. Vue实例中修改全局变量

在配置中已经将主应用传过来的prop对象参数,使用依赖注入的方式注入到全局

instance.provide('MAIN_APP_PROPS', props);

vue实例中可以使用inject获取这个参数,从而使用prop参数里面带的onGlobalStateChange、setGlobalState两个函数管理全局状态

/**
* test.vue TODO
* @Author ZhangJun
* @Date  2025/3/12 15:03
**/
<template>
 <el-card class="text-left">
   <template #header>
     <div>子应用1测试修改全局状态</div>
   </template>

   <div>
     <div>当前全局状态:</div>
     <div class="bg-blue-lighter">
       <el-input
           v-model="globalStateCache"
           style="width: 240px"
           :autosize="{ minRows: 2, maxRows: 4 }"
           type="textarea"
           placeholder="请输入新的全局状态"
       />
     </div>
   </div>
   <el-button style="margin-top: 10px" type="primary" @click="changeGlobalState()">修改全局状态</el-button>
 </el-card>
</template>

<script setup lang="ts">
import {inject, ref} from "vue";

const mainAppProps:any = inject('MAIN_APP_PROPS')

//全局状态缓存
const globalStateCache = ref('')

//监听全局状态变化
mainAppProps?.onGlobalStateChange((state:any,prev:any) => {
  if(JSON.stringify(state)!== JSON.stringify(prev)){
    globalStateCache.value = JSON.stringify(state)
  }
})

/**
 * 全局状态的修改
 */
const changeGlobalState = () => {
  let updateState = JSON.parse(globalStateCache.value)
  //更新全局状态
  mainAppProps?.setGlobalState(updateState)
}

</script>

<style scoped>
.bg-blue-lighter{
  background-color: #f0f9ff;
  color: #4a4a4a;
}
</style>

四、使用 Pinia 实现子应用独立状态管理

如果子应用需要独立管理状态,可以使用Pinia(推荐)或Vuex

1. 安装 Pinia

在子应用中安装Pinia

npm install pinia

2. 配置 Pinia

在子应用中创建Pinia实例并注入到应用中。

// subApp1/src/main.ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router';

let instance = null;

function render(props = {}) {
  const { container } = props;
  const app = createApp(App);
  const pinia = createPinia();

  app.use(pinia);
  app.use(router);
  instance = app.mount(container ? container.querySelector('#app') : '#app');
}

if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

export async function bootstrap() {
  console.log('subApp1 bootstrap');
}

export async function mount(props) {
  console.log('subApp1 mount');
  render(props);
}

export async function unmount() {
  console.log('subApp1 unmount');
  instance.unmount();
  instance = null;
}

3. 创建 Pinia Store

在子应用中创建Pinia Store

// subApp1/src/stores/userStore.js
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({
    name: 'SubApp1 User',
  }),
  actions: {
    updateName(newName) {
      this.name = newName;
    },
  },
});

4. 在组件中使用 Pinia Store

<!-- subApp1/src/App.vue -->
<template>
  <div>
    <h1>{{ userStore.name }}</h1>
    <button @click="updateName">Update Name</button>
  </div>
</template>

<script>
import { useUserStore } from './stores/userStore';

export default {
  setup() {
    const userStore = useUserStore();

    const updateName = () => {
      userStore.updateName('New SubApp1 User');
    };

    return {
      userStore,
      updateName,
    };
  },
};
</script>

五、使用 EventBus 实现子应用通信

如果子应用之间需要通信,可以使用EventBus

在主应用中创建一个全局事件总线,并将其注入到子应用中。

1. 创建 EventBus

在主应用中创建一个eventBus.js文件,用于导出事件总线实例。

// src/eventBus.js
import mitt from 'mitt'
const eventBus = mitt()
export default eventBus;

2. 主应用注入事件总线

在主应用中,通过registerMicroAppsprops参数将事件总线传递给子应用。

// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { registerMicroApps, start } from 'qiankun';
import eventBus from './eventBus';

const app = createApp(App);
app.use(router);
app.mount('#app');

// 注册子应用
registerMicroApps([
  {
    name: 'subApp1',
    entry: '//localhost:7101',
    container: '#subapp-container',
    activeRule: '/subApp1',
    props: {
      eventBus, // 将事件总线传递给子应用
    },
  },
  {
    name: 'subApp2',
    entry: '//localhost:7102',
    container: '#subapp-container',
    activeRule: '/subApp2',
    props: {
      eventBus, // 将事件总线传递给子应用
    },
  },
]);

// 启动 qiankun
start();

3. 在子应用中使用 EventBus

在子应用中,通过props获取事件总线,并使用它来发送和接收事件。

3.1 子应用1 发送事件

在子应用1中,通过事件总线发送事件。

<!-- subApp1/src/views/Home.vue -->
<template>
  <div>
    <h1>子应用1</h1>
    <button @click="sendMessage">发送消息</button>
  </div>
</template>

<script>
import { inject } from 'vue';

export default {
  setup() {
    const props = inject('props');
    const eventBus = props.eventBus;

    const sendMessage = () => {
      eventBus.emit('message-from-subApp1', {
        message: 'Hello from SubApp1',
      });
    };

    return {
      sendMessage,
    };
  },
};
</script>

3.2 子应用2 监听事件

在子应用2中,通过事件总线监听事件。

<!-- subApp2/src/views/Home.vue -->
<template>
  <div>
    <h1>子应用2</h1>
    <p>收到消息:{{ message }}</p>
  </div>
</template>

<script>
import { inject, ref, onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const props = inject('props');
    const eventBus = props.eventBus;
    const message = ref('');

    const handleMessage = (payload) => {
      message.value = payload.message;
    };

    onMounted(() => {
      eventBus.on('message-from-subApp1', handleMessage);
    });

    onUnmounted(() => {
      eventBus.off('message-from-subApp1', handleMessage);
    });

    return {
      message,
    };
  },
};
</script>

六、总结

  • 全局状态共享:使用 qiankuninitGlobalState 方法。
  • 子应用独立状态管理:使用 PiniaVuex
  • 子应用通信:使用 EventBusCustomEvent

相关文章:

  • 【GL008】C++ 入门基础(2)之 多态案例
  • centos【rockylinux】安装【supervisor】的注意事项【完整版】
  • Android开发中的Native 调试
  • Go语言的基础类型
  • STM32和PN532 寻卡实验
  • Springboot项目打包成war包
  • 西门子PLC
  • Freeze-Omni:冻结 LLM,实现语音对话
  • 半导体过程控制篇6 设计质量控制SPC
  • ​第十一届传感云和边缘计算系统国际会议
  • python中测试数据管理整理
  • Spring Cloud之负载均衡之LoadBalance
  • 汇川EASY系列之以太网通讯(MODBUS_TCP做主站)
  • 【工具变量】人口老龄化对经济增长影响数据集(2005-2023年)
  • Python列表1
  • 3.19学习总结
  • 【MySQL基础-10】MySQL中的LENGTH()函数:用法详解与实例分析
  • C语言中,memmove和memcpy的区别?
  • Linux 文件操作-标准IO函数3- fread读取、fwrite写入、 fprintf向文件写入格式化数据、fscanf逐行读取格式化数据的验证
  • 【C#语言】C#中的同步与异步编程:原理、示例与最佳实践
  • 对谈|李钧鹏、周忆粟:安德鲁·阿伯特过程社会学的魅力
  • 王毅会见俄罗斯外长拉夫罗夫
  • 人社部:我国劳动力市场潜力足,韧性强
  • 人民时评:投资于人,促高质量充分就业
  • 当隐身13年的北小京决定公开身份 ,专业戏剧评论依然稀缺
  • 这些被低估的降血压运动,每天几分钟就管用