Pinia

19 阅读1分钟

如何使用pinia

首先进行安装:npm install pinia

创建一个pinia并注册

src
├─ App.vue
├─ main.js
├─ stores
│    ├─ counter.js
│    ├─ home.js
│    ├─ index.js
│    └─ user.js
└─ views
       ├─ 01_pinia的基本使用.vue
       ├─ 02_Pinia的核心State.vue
       ├─ 03_Pinia的核心Getters.vue
       └─ Home.vue
import { createPinia } from 'pinia'

const pinia = createPinia()

export default pinia

import { createApp } from 'vue'
import App from './App.vue'
import pinia from './stores'


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

定义一个Store:我们需要知道 Store 是使用 defineStore() 定义的,并且它需要一个唯一名称,作为第一个参数传递,这个name,也称为id,是必要的,Pinia 使用它来将 store 连接到 devtools,返回的函数统一使用useX作为命名方案,这是约定的规范

// 定义关于counter的store
import { defineStore } from 'pinia'

import useUser from './user'

const useCounter = defineStore("counter", {
  state: () => ({
    count: 99,
  }),
})

export default useCounter

Store在它被使用之前是不会创建的,我们可以通过调用use函数来使用Store 注意Store获取到后不能被解构,那么会失去响应式,为了从 Store 中提取属性同时保持其响应式,您需要使用storeToRefs()

<template>
  <div class="home">
    <h2>Home View</h2>
    <h2>count: {{ counterStore.count }}</h2>
    <h2>count: {{ count }}</h2>
    <button @click="incrementCount">count+1</button>
  </div>
</template>

<script setup>
  import { toRefs } from 'vue'
  import { storeToRefs } from 'pinia'
  import useCounter from '@/stores/counter';

  const counterStore = useCounter()

  // const { count } = toRefs(counterStore)
  const { count } = storeToRefs(counterStore)


  function incrementCount() {
    counterStore.count++
  }

</script>

<style scoped>
</style>

认识和定义State

state 是 store 的核心部分,因为store是用来帮助我们管理状态的,在 Pinia 中,状态被定义为返回初始状态的函数

import { defineStore } from 'pinia'

const useUser = defineStore("user", {
  state: () => ({
    name: "why",
    age: 18,
    level: 100
  })
})

export default useUser

读取和写入State:

  • 默认情况下,您可以通过 store 实例访问状态来直接读取和写入状态
  • 你可以通过调用 store 上的 $reset() 方法将状态重置到其初始值
  • 除了直接用 store.counter++ 修改 store,你还可以调用 $patch 方法
  • 您可以通过将其 $state 属性设置为新对象来替换 Store 的整个状态
<template>
  <div class="home">
    <h2>Home View</h2>
    <h2>count: {{ counterStore.count }}</h2>
    <h2>count: {{ count }}</h2>
    <button @click="incrementCount">count+1</button>
  </div>
</template>

<script setup>
  import { toRefs } from 'vue'
  import { storeToRefs } from 'pinia'
  import useCounter from '@/stores/counter';

  const counterStore = useCounter()

  // const { count } = toRefs(counterStore)
  const { count } = storeToRefs(counterStore)


  function incrementCount() {
    counterStore.count++
  }

</script>

<style scoped>
</style>


认识和定义Getters

Getters相当于Store的计算属性:

  • 它们可以用 defineStore() 中的 getters 属性定义
  • getters中可以定义接受一个state作为参数的函数
  • 访问其他store的Getters
  • Getters也可以返回一个函数,这样就可以接受参数
// 定义关于counter的store
import { defineStore } from 'pinia'

import useUser from './user'

const useCounter = defineStore("counter", {
  state: () => ({
    count: 99,
    friends: [
      { id: 111, name: "why" },
      { id: 112, name: "kobe" },
      { id: 113, name: "james" },
    ]
  }),
  getters: {
    // 1.基本使用
    doubleCount(state) {
      return state.count * 2
    },
    // 2.一个getter引入另外一个getter
    doubleCountAddOne() {
      // this是store实例
      return this.doubleCount + 1
    },
    // 3.getters也支持返回一个函数
    getFriendById(state) {
      return function(id) {
        for (let i = 0; i < state.friends.length; i++) {
          const friend = state.friends[i]
          if (friend.id === id) {
            return friend
          }
        }
      }
    },
    // 4.getters中用到别的store中的数据
    showMessage(state) {
      // 1.获取user信息
      const userStore = useUser()

      // 2.获取自己的信息

      // 3.拼接信息
      return `name:${userStore.name}-count:${state.count}`
    }
  }
})

export default useCounter

<template>
  <div class="home">
    <h2>Home View</h2>
    <h2>doubleCount: {{ counterStore.doubleCount }}</h2>
    <h2>doubleCountAddOne: {{ counterStore.doubleCountAddOne }}</h2>
    <h2>friend-111: {{ counterStore.getFriendById(111) }}</h2>
    <h2>friend-112: {{ counterStore.getFriendById(112) }}</h2>
    <h2>showMessage: {{ counterStore.showMessage }}</h2>
    <button @click="changeState">修改state</button>
    <button @click="resetState">重置state</button>
  </div>
</template>

<script setup>
  import useCounter from '@/stores/counter';

  const counterStore = useCounter()

</script>

<style scoped>
</style>


认识和定义Action

Actions 相当于组件中的 methods, 可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑 和getters一样,在action中可以通过this访问整个store实例的所有操作

// 定义关于counter的store
import { defineStore } from 'pinia'

import useUser from './user'

const useCounter = defineStore("counter", {
  state: () => ({
    count: 99,
    friends: [
      { id: 111, name: "why" },
      { id: 112, name: "kobe" },
      { id: 113, name: "james" },
    ]
  }),
  getters: {
    // 1.基本使用
    doubleCount(state) {
      return state.count * 2
    },
    // 2.一个getter引入另外一个getter
    doubleCountAddOne() {
      // this是store实例
      return this.doubleCount + 1
    },
    // 3.getters也支持返回一个函数
    getFriendById(state) {
      return function(id) {
        for (let i = 0; i < state.friends.length; i++) {
          const friend = state.friends[i]
          if (friend.id === id) {
            return friend
          }
        }
      }
    },
    // 4.getters中用到别的store中的数据
    showMessage(state) {
      // 1.获取user信息
      const userStore = useUser()

      // 2.获取自己的信息

      // 3.拼接信息
      return `name:${userStore.name}-count:${state.count}`
    }
  },
  actions: {
    increment() {
      this.count++
    },
    incrementNum(num) {
      this.count += num
    }
  }
})

export default useCounter

import { defineStore } from 'pinia'

const useHome = defineStore("home", {
  state: () => ({
    banners: [],
    recommends: []
  }),
  actions: {
    async fetchHomeMultidata() {
      const res = await fetch("http://123.207.32.32:8000/home/multidata")
      const data = await res.json()

      this.banners = data.data.banner.list
      this.recommends = data.data.recommend.list
      
      // return new Promise(async (resolve, reject) => {
      //   const res = await fetch("http://123.207.32.32:8000/home/multidata")
      //   const data = await res.json()

      //   this.banners = data.data.banner.list
      //   this.recommends = data.data.recommend.list

      //   resolve("bbb")
      // })
    }
  }
})

export default useHome

<template>
  <div class="home">
    <h2>Home View</h2>
    <h2>doubleCount: {{ counterStore.count }}</h2>
    <button @click="changeState">修改state</button>


    <!-- 展示数据 -->
    <h2>轮播的数据</h2>
    <ul>
      <template v-for="item in homeStore.banners">
        <li>{{ item.title }}</li>
      </template>
    </ul>
  </div>
</template>


<script setup>
  import useCounter from '@/stores/counter';
  import useHome from '@/stores/home';


  const counterStore = useCounter()


  function changeState() {
    // counterStore.increment()
    counterStore.incrementNum(10)
  }


  const homeStore = useHome()
  homeStore.fetchHomeMultidata().then(res => {
    console.log("fetchHomeMultidata的action已经完成了:", res)
  })


</script>


<style scoped>
</style>