自学内容网 自学内容网

Vue3探索编辑部——关于Pinia(1)

目录

什么是Pinia?

Vue3中的Pinia

创建项目

数据准备和引入Pinia

使用Pinia

采用action修改数据

总结


什么是Pinia?

       Pinia是Vue3的专属的状态管理工具,什么是状态呢?其实我们可以把状态理解为数据,或者一个业务逻辑实体,都可以为状态。Pinia是Vue3的状态管理工具,这是Vuex的替代工具,不过它比Vuex简单直接很多,省去了很多语法。Vue3的一个重要思想就是数据为尊,加之Vue3是在之前的Vue的基础上的优化升级,所以简洁明了了很多 Pinia的引入,成功的解决了当组件繁多,不同组件之间有很多数据嵌套,包含的情况的时候,我们写代码繁重,逻辑不清晰的问题 #几大特点

  • 提供了更加简单的API,去掉了mutation

  • 提供更加贴近组合式API的新语法,并且和Vue3的其他语法统一

  • 去掉了modules的概念,每个store都是一个独立的模块

  • 对于TypeScript更加友好,类型推断更加可靠

  • 对于插件的支持更加好,我们可以根据项目的特定需求来自定义状态管理 #代码演示

Vue3中的Pinia

创建项目

       首先我们创建一个Vue3的项目,来专门演练一下Pinia。首先就是按照Vue3官方网站的步骤,创建项目,然后在选项工具这一步的时候,选择Pinia工具的时候,选上Yes,语言你可以用JavaScript,也可以是TypeScript都行。

npm create vue@latest
✔ Project name: … <your-project-name> 
✔ Add TypeScript? … No / Yes ✔ Add JSX Support? … No / Yes 
✔ Add Vue Router for Single Page Application development? … No / Yes 
✔ Add Pinia for state management? … No / Yes 
✔ Add Vitest for Unit testing? … No / Yes 
✔ Add an End-to-End Testing Solution? … No / Cypress / Playwright 
✔ Add ESLint for code quality? … No / Yes 
✔ Add Prettier for code formatting? … No / Yes Scaffolding project in ./<your-project-name>... Done

数据准备和引入Pinia

       下面我们来到代码部分,我用的是Webstorm,其他编辑器也是一样,文件目录都是这样,我们可以看到src文件目录下的stores文件,里面有个js文件movie.js,这个就是我们引入Pinia的地方。由于我们在创建项目的时候,选择了引入Pinia,那么在stores文件下,就会有一个counter.js文件,这里我重命名为了movie.js,下面的代码是这个js文件原本的样子。

       下面的代码分别是movie.js文件和main.js文件,我们都按照官方的写法去一步一步地引入,写代码按照官方规范。

import { ref, computed } from 'vue'  
import { defineStore } from 'pinia'  
  
//我们还想完成什么样的功能,在这里写功能代码,然后在其他组件引入就可以直接使用了  
export const useCounterStore = defineStore('counter', () => {  
  const count = ref(0)  
  const doubleCount = computed(() => count.value * 2)  
  function increment() {  
    count.value++  
  }  
  
  return { count, doubleCount, increment }  
})
import { createApp } from 'vue'
//第一步:引入pinia
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
​
//第二步:创建pinia
const app = createApp(App)
​
//第三步:安装pinia
app.use(createPinia())
​
app.use(router)
app.mount('#app')
​

       下面我们就可以在组件中使用Pinia工具了,当然,把其他所有的.vue的组件和相应的引入全都删掉,我们就只看Pinia所要完成的功能,我们在components文件夹下新建一个.vue组件,叫Movies.vue,我们在这个组件内编写功能。

<script setup name="Movies">  
import {reactive} from "vue";  
  
//数据  
let movieList = reactive([  
  {id:1,title:'火星救援'},  
  {id:2,title:'搏击俱乐部'},  
  {id:3,title:'流浪地球2'}  
])  
  
//要完成的功能  
async function getMovie(){  
  //发送请求,连续解构赋值,然后再重命名  
}  
</script>  
  
<template>  
  <div class="movie">  
    <button @click="getMovie">获取一部电影</button>  
    <ul>      
    <li v-for="movie in movieList" :key="movie.id">{{movie.title}}</li>  
    </ul>  
  </div>  
</template>  
  
<style scoped>  
.movie {  
  background-color: orange;  
  padding: 10px;  
  border-radius: 10px;  
  box-shadow: 0 0 10px;  
}  
</style>

       我们在Movies.vue组件中,写一些基本的功能,三个对象形式的数据,用reactive包裹,采用v-for遍历这个对象数组,并且在App.vue中引入Movies这个组件。

<script setup>  
import Movies from "@/components/Movies.vue";  
</script>  
  
<template>  
  <div>  
    <h2>  
      我是App.vue  
    </h2>  
  </div>  
  <Movies>  
  </Movies>
</template>  
  
<style scoped>  
  
</style>

       启动项目,不管你是用npm,yarn还是pnpm,都是一样的,我们打开浏览器就能看到这样的效果。

       接下来,我们引入axios,发送一个请求,这里我就直接用一个现成的网站了,https://api.uomg.com/api/rand.qinghua?format=json,这是尚硅谷的一个服务器网站。

       在Movies.vue组件中写下这样的代码,读者可以先不必纠结这一部分,我们的重点不是这里,这里都是一些铺垫工作,总之这里的async部分是一个功能。

<script setup name="Movies">  
import {reactive} from "vue";  
import axios from "axios";  
import {nanoid} from 'nanoid'  
  
//数据  
let movieList = reactive([  
  {id:1,title:'火星救援'},  
  {id:2,title:'搏击俱乐部'},  
  {id:3,title:'流浪地球2'}  
])  
  
//要完成的功能  
async function getMovie(){  
  //发送请求,连续解构赋值,然后再重命名  
  let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')  
  //把请求回来的字符串,处理成一个对象  
  let obj = {id:nanoid(),title}  
  //再放到数组中  
  movieList.unshift(obj)  
}  
</script>  
  
<template>  
  <div class="movie">  
    <button @click="getMovie">获取一部电影</button>  
    <ul>      
    <li v-for="movie in movieList" :key="movie.id">{{movie.title}}</li>  
    </ul>  
  </div>  
</template>  
  
<style scoped>  
.movie {  
  background-color: orange;  
  padding: 10px;  
  border-radius: 10px;  
  box-shadow: 0 0 10px;  
}  
</style>

使用Pinia

       我们会看到Vue开发者工具中就有了Pinia,stores文件夹就是Pinia的一个具体体现,我们就把store下的movie.js想象成一个仓库,我们在这里完成功能代码,来处理刚才的Movies.vue。stores文件夹下的js代码,里面就存有,Pinia要管理的状态,可以是数据,也可也是方法

import { defineStore } from 'pinia'  
  
//我们还想完成什么样的功能,在这里写功能代码,然后在其他组件引入就可以直接使用了  
export const useMovieStore = defineStore('movie',{  
  //数据真正存储的地方  
  state(){  
    return {  
      movieList:[  
          {id:1,title:'火星救援'},  
          {id:2,title:'搏击俱乐部'},  
          {id:3,title:'流浪地球2'}  
      ]  
    }  
  }  
})

       然后回到Movies.vue中,我们可以去掉之前写的数据了,即movieList,因为数据已经存放到stores下的movie.js下,使用Pinia管理了,可以先把getMovie()中的代码注释一下,我们只需要在这里import引入useMovieStore,再声明一个变量movieStore,就可以使用数据了,数据存储在movie.js,而在Movie.vue组件中使用。

<script setup name="Movies">  
import {reactive} from "vue";  
import axios from "axios";  
import {nanoid} from 'nanoid'  
import {useMovieStore} from "@/stores/counter.js";  
  
//数据  
// let movieList = reactive([  
//   {id:1,title:'火星救援'},  
//   {id:2,title:'搏击俱乐部'},  
//   {id:3,title:'流浪地球2'}  
// ])  
  
//使用pinia后,我们就这样使用数据了  
const MovieStore = useMovieStore()  
  
//要完成的功能  
async function getMovie(){  
  //发送请求,连续解构赋值,然后再重命名  
  //let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')  
  //把请求回来的字符串,处理成一个对象  
  //let obj = {id:nanoid(),title}  
  //再放到数组中  
  //movieList.unshift(obj)  
}  
</script>  
  
<template>  
  <div class="movie">  
    <button @click="getMovie">获取一部电影</button>  
    <ul>      <li v-for="movie in MovieStore.movieList" :key="movie.id">{{movie.title}}</li>  
    </ul>  
  </div>  
</template>  
  
<style scoped>  
.movie {  
  background-color: orange;  
  padding: 10px;  
  border-radius: 10px;  
  box-shadow: 0 0 10px;  
}  
</style>

       这是打开开发者工具的效果,这就是存储数据的过程,先引入Pinia,再在stores下的movie.js下,存入数据。

采用action修改数据

       数据存放好了,如果我们要对数据做改动,或者围绕数据要写一些方法,我们要采用Action,Action相当于组件中的method,它们可以通过defineStore()中的actions属性来定义。回到movie.js文件中,把之前的函数体弄到这里来,之前在Movies.vue的函数中的相应部分我们就可以删除了,功能写在这里,这样movieList数据和其相关的方法都在这一份代码中,简洁高效,思路清晰。

import { defineStore } from 'pinia'
import axios from "axios";
import {nanoid} from "nanoid";
​
//我们还想完成什么样的功能,在这里写功能代码,然后在其他组件引入就可以直接使用了
export const useMovieStore = defineStore('movie',{
    //要完成什么样的逻辑,我们就在actions里面写
    actions:{
         async getMovies(){
            //发送请求,连续解构赋值,然后再重命名
            let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
            //把请求回来的字符串,处理成一个对象
            let obj = {id:nanoid(),title}
            //再放到数组中
            this.movieList.unshift(obj)
        }
    },
    //数据真正存储的地方
    state(){
        return {
          movieList:[
              {id:1,title:'火星救援'},
              {id:2,title:'搏击俱乐部'},
              {id:3,title:'流浪地球2'}
          ]
        }
  }
})

       同时,如果我们想要在Vue组件中保持对Pinia存储中的响应式状态的直接引用,具体到这里,就是要让movieList具有响应式特性,就要使用storeToRefs来包裹movieList。

<script setup name="Movies">
import {useMovieStore} from "@/stores/movie.js";
import { storeToRefs } from "pinia";
//数据
// let movieList = reactive([
//   {id:1,title:'火星救援'},
//   {id:2,title:'搏击俱乐部'},
//   {id:3,title:'流浪地球2'}
// ])
​
//使用pinia后,我们就这样使用数据了
const MovieStore = useMovieStore()
//我们要用storeToRefs包裹,storeToRefs只会关注store中的数据,不会对方法进行ref包裹
const { movieList } = storeToRefs(MovieStore)
​
function getMovie(){
  MovieStore.getMovies()
}
​
</script>
​
<template>
  <div class="movie">
    <button @click="getMovie">获取一部电影</button>
    <ul>
      <li v-for="movie in movieList" :key="movie.id">{{movie.title}}</li>
    </ul>
  </div>
</template>
​
<style scoped>
.movie {
  background-color: orange;
  padding: 10px;
  border-radius: 10px;
  box-shadow: 0 0 10px;
}
</style>

总结

       Pinia 是 Vue 3 的状态管理库,用于简化和集中管理应用的状态和逻辑。它提供了简洁的 API 和良好的 TypeScript 支持。在以上的代码中,Pinia 用于存储和管理电影列表数据,通过 defineStore 创建 store,使用 actions 处理异步获取电影数据的逻辑。通过 storeToRefs,可以在 Vue 组件中保持对 Pinia store 中状态的响应式引用,确保当 store 中的状态更新时,组件能够实时反映这些变化。


原文地址:https://blog.csdn.net/weixin_47166204/article/details/135887628

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!