零基础教学:Vue3 + Pinia实现组件共享数据(使用相同数据的组件只需向服务器发送一次请求)

零基础教学:Vue3 + Pinia实现组件共享数据(使用相同数据的组件只需向服务器发送一次请求)

简介

在Vue项目中,当两个/多个组件需要用到相同的服务器数据时,如果分别在各自组件内向服务器请求数据,无疑会增加服务器负担。这里可以用Pinia来实现共享数据,从而只需向服务器发送一次请求。

必须有一个父组件作为桥梁(两个子组件为相同数据的使用者)
不一定是父组件,只要是层级更高的组件都可以作为桥梁,比如一级组件作为桥梁,其它二级组件作为数据使用者,如图:
可将图中index.vue视作一级组件,components文件夹内的HomeCategory.vue等视作二级组件。文末有结合代码的详细解释。

文件等级划分截图)

原理图:
原理图

组件分布

这里取三个组件,Son1, Son2都为Father的儿子组件

  • Father.vue
  • Son1.vue
  • Son2.vue

代码实现及解释

1. 安装pinia

  • 终端输入:
npm i pinia
  • 在根目录下的main.js中使用pinia插件
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')

2. 通过pinia创建需要共享的方法和数据

  • src/stores下创建.js文件categoryStore.js(路径、名字可自定义)。最后returncategoryList为需要的服务器返回的数据getCategory向服务器发送请求的方法 。(getCategoryAPI 是二次封装axios后调用的函数,这里只需要知道它是发送请求的就行)
//categoryStore.js
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { getCategoryAPI } from '@/apis/layout'
export const useCategoryStore = defineStore('category', () => {
  // 导航列表的数据管理
  // state
  const categoryList = ref([])

  // action 获取导航数据的方法
  const getCategory = async () => {
    const res = await getCategoryAPI()
    categoryList.value = res.result
  }

  return {
    categoryList,
    getCategory
  }
})
  • Father.vue中:
<script setup>

//引入子组件
import Son1 from './components/Son1.vue'
import Son2 from './components/Son2.vue'
import { onMounted } from 'vue'

// 触发获取导航列表的action
import { useCategoryStore } from '@/stores/categoryStore'

// 调用categoryStore.js中的useCategoryStore创建对象(pinia的基操,这里看不懂可以随便搜一篇pinia的入门教学,很简单)
const categoryStore = useCategoryStore()
//调用getCategory,向服务器发送请求,也是唯一一次发送请求!!!(关键)
onMounted(() => categoryStore.getCategory())
</script>

<template>
  <Son1/>
  <Son2/>
</template>
  • Son1.vueSon2.vue代码相同,这里是Son1.vue的:
// 这两行和上面的Father.vue一样
import { useCategoryStore } from '@/stores/categoryStore'

const categoryStore = useCategoryStore()

//接下来就可以直接使用categoryList了,比如用来v-for遍历。如果Son2.vue中也需要用到这些数据,同样只需要以上两行
<li class="home" v-for="item in categoryList" :key="item.id">{{ item.name }}</li>
  • 解释
  1. 为什么是在Father.vue中创建实例并发送请求而不是在两个子组件中?
    因为若是在子组件中分别发送请求,就没有达到为服务器"减负"的目的,同样需要发送两次请求。
  2. 为什么两个子组件中可以直接使用categoryList?
    因为在Father.vue中已经向服务器发送了请求(调用了getCategory方法),并将服务器返回的数据赋值给了categoryList。两个子组件之所以调用useCategoryStore()方法,是为了通过这个方法创建的实例对象categoryStore来取得categoryList并使用,并不需要再调用getCategory向服务器发送请求。

因此总的来说只发送了一次服务器请求,实现了数据复用的同时减轻了服务器压力。

3. 非直接父子关系组件的情况

现在举例解释文章开头所说的只要是路由等级更高的组件都可以作为桥梁

文件等级划分截图
比如我在Layout/index.vue中使用了上文中Father.vue中的同样代码,即向服务器请求数据;那么在Home/HomeCategory.vue中,我也可以像上文中Son1.vue中那样创建实例对象categoryStore来取得categoryList并使用,尽管这两个组件并非直接父子组件关系。代码完全一样:

import { useCategoryStore } from '@/stores/categoryStore'

const categoryStore = useCategoryStore()

<li class="home" v-for="item in categoryList" :key="item.id">{{ item.name }}</li>

我的理解是因为更高层级的组件先加载,加载后就发送了数据请求并将结果保存在categoryList中,所以后调用的次一级组件创建categoryStore 实例对象时,categoryList已经可以具备了刚刚请求返回的数据。因此只要是层级更高的组件都可以作为桥梁请求数据,这样所有使用相同数据的次级组件都只需请求一次。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值