Pinia ! 一篇文章足矣学会🍍

1,690 阅读3分钟

Pinia大菠萝🍍

1.为什么需要pinia

  • Pinia最初只是为了初探Vuex的下一次迭代是什么样子,结合了Vuex5 核心团队讨论中的许多想法

  • 最终,团队意识到Pinia已经实现了Vuex5中大部分内容,所以最终决定用Pinia来替代Vuex;

  • 与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的仪式,提供了 Composition-API 风格的 API;

  • 最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持;

  • 和Vuex相比,Pinia有许多优势:

    • mutations不再存在,因为mutations通常被认为是非常冗长

    • 更友好的Typescript支持,Vuex对TS支持并不友好

    • 不再有modules的嵌套结构:

      • 可以灵活使用每一个store,它们是通过扁平化的方式来相互使用


2.如何使用Pinia

以下步骤都是以脚手架形式开发的,所以学习pinia之前请下载个脚手架生成项目

  • 2.1:第一步当然是下载Pinia辣
  • 2.2:创建stores/index.js作为入口文件
  • 2.3:去到main.js中导入
  • 2.4:创建counter.js
yarn add pinia
#or with npm
npm install pinia
//stores/index.js
import {createPinia} from "pinia";
const pinia = createPinia();
export default pinia
//main.js
import pinia from './stores'
//counter.js
//定义关于counter的store
import {defineStore} from "pinia"//defineStore返回的是一个函数
const useCounterStore = defineStore("counter",{
  state:() => ({
    count:99
  })
})
​
export default useCounterStore

创建Home组件

<template>
  <div class="home">
    <h2>
      Home View
    </h2>
    <h2>count:{{CounterStore.count}}</h2> 
    <h2>count:{{count}}</h2> 
    <button @click="increment">
      点击更新count
    </button>
  </div>
</template>
<script setup>
  import useCounterStore from "@/stores/counter"
  import {storeToRefs} from "pinia" //pinia提供的响应式
  const CounterStore = useCounterStore()
  //也可以进行结构
  const {count} = storeToRefs(CounterStore)
  
  const increment = () => {
    CounterStore.count++
  }
  
</script>

在App.vue中导入Home组件

<template>
  <Home />
</template>
<script setup>
  import Home from "./views/Home.vue"
</script>

3.State的使用与认识

3.1.创建user.js文件

import {defineStore} from "pinia"const useUserStores = defineStore("user",{
  state:()=> ({
    name:"tim",
    age:21,
    level:20
  })
})
​
export default useUserStores
<template>
  <div class="home">
    <h2>
      Home View
    </h2>
    <h2>name:{{name}}</h2>
    <h2>age:{{age}}</h2>
    <h2>level:{{level}}</h2>
  </div>
</template>
<script setup>
  import useUserStore from "pinia" 
  const useUserStore = useUserStores()
  const {name,age,level} = storeToRefs(useUserStore)
  
</script>

3.2.操作State

  • 1.认识不同方式的操作State数据
  • 2.使用$reset()进行数据重置(数据一开始pinia会进行缓存)
<template>
  <div class="home">
    <h2>
      Home View
    </h2>
    <h2>name:{{name}}</h2>
    <h2>age:{{age}}</h2>
    <h2>level:{{level}}</h2>
    <button @click="changeState">修改state</button>
    <button @click="resetState">重置state</button>
  </div>
</template>
<script setup>
  import useUserStore from "pinia" 
  const useUserStore = useUserStores()
  const {name,age,level} = storeToRefs(useUserStore)
  //修改State
  const changeState = () => {
    //1. 一次只修改一个状态
    //useUserStore.name = "kobe",
    //useUserStore.age = "18",
    //useUserStore.level = 100
    
    //2. 一次修改所有状态
    //useUserStore.$patch({
      //name:"james",
      //age:35
    //})
    
    //3. 替换state为新的对象 (很少使用)
    useUserstore.$state = {
      name:"姚明",
      level:80
    }
  }
  //重置State
  const resetState = () => {
    useUserStore.$reset() //可以重置到初始化状态,因为一开始就缓存了初始化状态
  }
</script>

4.认识Getters

  • 它们可以用 defineStore() 中的 getters 属性定义;
  • getters中可以定义接受一个state作为参数的函数;
  • getter相当于Store的计算属性

4.1定义Getters

  • 1.使用getters:{定义函数(state)} 函数里面提供了state数据可以直接获取 || getters里面可以直接是用this获取
  • 2.getters引入另外一个getters的使用
  • 3.getters支持返回函数
  • 4.getters中使用别的store中数据
//counter.js
//定义关于counter的store
import {defineStore} from "pinia"
import {useUserStores} from "./user"
//defineStore返回的是一个函数
const useCounterStore = defineStore("counter",{
  state:() => ({
    count:99,
    person: [
      {id:1,name:"周冬雨"},
      {id:2,name:"周杰伦"},
      {id:3,name:"周笔畅"}
    ]
  }),
  getters: {
    //1.基本使用
    doubleCount(state) {
      return state.count * 2
    }
    doubleCountChange() {
      return this.doubleCount + '🫐'
    }
    getPersonId(state) {
      return function(id) {
        return state.person.filter(item => item.id === id)
      }
    }
    showMessage() {
      //1.获取user信息
      const useUserStore = useUserStores()
      //2.获取本文件信息
      
      //3.拼接信息
      return `name:${useUserStore.name}-count:${state.count}`
    }
  }
})
​
export default useCounterStore
<template>
  <div class="home">
    <h2>
      Home View
    </h2>
    <h2>doubleCount: {{CounterStore.doubleCount}}</h2>
    <h2>
      doubleCountChange: {{CounterStore.doubleCountChange}}
    </h2>
    <h2>
      getPersonId: {{CounterStore.getPersonId(2)}}
    </h2>
     <h2>
      showMessage: {{CounterStore.showMessage}}
    </h2>
  </div>
</template>
<script setup>
  import useCounterStore from "@/stores/counter"
  import {storeToRefs} from "pinia" //pinia提供的响应式
  const CounterStore = useCounterStore()
  
  
</script>

5.认识和定义Actions

Actions相当于组件中的methods

  • 可以使用defineStore()中的actions属性定义,并且它们非常适合定义业务逻辑
  • Actions和Getters一样可以使用this访问整个store实例的所有操作

5.1定义actions

//counter.js
//定义关于counter的store
import {defineStore} from "pinia"
import {useUserStores} from "./user"
//defineStore返回的是一个函数
const useCounterStore = defineStore("counter",{
  state:() => ({
    count:99,
    person: [
      {id:1,name:"周冬雨"},
      {id:2,name:"周杰伦"},
      {id:3,name:"周笔畅"}
    ]
  }),
  getters: {
    //1.基本使用
    doubleCount(state) {
      return state.count * 2
    }
    doubleCountChange() {
      return this.doubleCount + '🫐'
    }
    getPersonId(state) {
      return function(id) {
        return state.person.filter(item => item.id === id)
      }
    }
    showMessage() {
      //1.获取user信息
      const useUserStore = useUserStores()
      //2.获取本文件信息
      
      //3.拼接信息
      return `name:${useUserStore.name}-count:${state.count}`
    }
  },
  actions: {
    increment(state) {
      console.log(state) //actions没有state,参数是传递的参数
      this.count++
    }
  }
})
​
export default useCounterStore
<template>
  <div class="home">
    <h2>
      Home View
    </h2
    <h2>
      doubleCount: {{count}}
    </h2>
    <button @click="changeState">修改state</button>
  </div>
</template>
<script setup>
  import useCounterStore from "@/stores/counter"
  import {storeToRefs} from "pinia" //pinia提供的响应式
  const CounterStore = useCounterStore()
  const {count} = storeToRefs(CounterStore)
  function changeState() {
    CounterStore.increment()
  }
</script>

5.2.actions异步操作

  • 1.定义home.js,并且提前给state给数据类型(随便提一嘴,pinia和ts会了之后,简直无敌)
  • 2.定义actions获取数据并且赋值给state
  • 3.在home.vue中使用
//home.js
import {defineStore} from "pinia"const useHomeStores = defineStore("home",{
  state: ()=> ({
    banners:[],
    recommends:[]
  })
  actions: {
    async fetchHome() {
      const response = await fetch("http://localhost:8000/home")
      const data = await response.json()
      this.banners = data.data.banner
    }
  }
})
​
export default useHomeStores
<template>
  <div class="home">
    <h2>
      Home View
    </h2>
    <ul>
      <li v-for="item in banners">
        <img :src="item">
      </li>
    </ul>
  </div>
</template>
<script setup>
  import useHomeStores from "@/stores/home"
  import {storeToRefs} from "pinia"
  const useHomeStore = useHomeStores()
  const {banners} = storeToRefs(useHomeStore)
  useHomeStore.fetchHomeMultidata().then(res=> {
    console.log("请求完成",res)
  })
</script>