Pinia的使用(以vue3+ts+vite为例)

Pinia

Pinia官方文档

Pinia GitHub地址

1. 安装

yarn add pinia
# 或者使用 npm
npm install pinia

2. 引入vue3

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

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

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

3. 初始化store仓库

在这里插入图片描述

定义一个名称枚举(store-name.ts)

export enum Names {
  TEST = 'test',
  USER = 'user'
}

定义store

import { defineStore, storeToRefs } from 'pinia'
import { Names } from './store-name'

// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
// defineStore() 的第二个参数可接受两类值:Setup 函数或 Option 对象。

// options API
export const useTestStore = defineStore(Names.TEST, {
  state: () => ({ name: '多多', count: 1 }),
  getters: {  // computed 修饰的一些值
    double: (state) => state.count * 2,
  },
  actions: {  // methods 同步异步 提交state
    increment() {
      this.count++
    },
  }
})

interface User {
  name: string
  age: number
}

// setup
export const useUserStore = defineStore(Names.USER, () => {
  // setup中:ref等于state  computed等于getters methods等于actions
  const name = ref('图图')
  const age = ref(18)
  const userMsg = computed(() => {
    return `我叫${name.value},我${age.value}岁了`
  })
  const setUser = (user: User) => {
    name.value = user.name
    age.value = user.age
  }

  return { name, age, userMsg, setUser }
})

使用store

<template>
  <div>USER:{{ user.name }} --- {{ user.age }} --- {{ user.userMsg }}</div>
</template>

<script setup lang="ts">
import { useUserStore } from '@/store'

const user = useUserStore()

</script>

4. 修改state

修改state的几种方法:

  1. 直接修改: user.name = '改变了'
  2. $patch(): user.$patch({name: 'patch对象改变'})
  3. $patch((state)=>{}): 好处是可以写修改逻辑, user.$patch((state)=>{ state.name = 'patch工厂函数' })
  4. $state: 不常用,需要修改全部值,不然ts类型报错, user.$state = {name: 'state改变', age: 18}
  5. action: 使用store内的方法 user.setUser({ name: '多多', age: 20 })
interface User {
  name: string
  age: number
}

export const useUserStore = defineStore(Names.USER, () => { // setup
  const name = ref('图图')
  const age = ref(18)
  
  const setUser = (user: User) => {
    !!user.name && (name.value = user.name)
    !!user.age && (age.value = user.age)
  }

  return { name, age, userMsg, setUser }
})

5. 解构store

pinia中,state相当于reactive不能直接解构,会失去响应性,pinia提供了 storeToRefs() 使其解构响应性不丢失

import { storeToRefs } from 'pinia';

const user = useUserStore()
const { name, age } = storeToRefs(user)

6. store中的方法和计算属性(actions、getters)

同步异步方法都可以,也可以进行互相调用

interface User {
  name?: string
  age?: number
}

const asyncData = () => {
  return new Promise<User>((resolve, reject) => {
    setTimeout(()=>{
      resolve({name: '异步', age: 20})
    },2000)
  })
}

export const useUserStore = defineStore(Names.USER, () => { // setup
  // setup中:ref等于state  computed等于getters methods等于actions
  const name = ref('图图')
  const age = ref(18)

  const ageMsg = computed<string>(()=>{
    return `${age.value}岁了`
  })

  const userMsg = computed<string>(() => {
    return `我叫${name.value}${ageMsg.value}`
  })

  // 同步
  const setUser = (user: User) => {
    !!user.name && (name.value = user.name)
    !!user.age && (age.value = user.age)
  }
  
  // 异步
  const asyncSetUser = async () => {
    const res = await asyncData()
    setUser(res)
  }


  return { name, age, userMsg, setUser, asyncSetUser }
})

7. API

7.1 $reset

重置state初始值,注意只在options API有用,setup函数模式报错

const test = useTestStore()
...
test.$reset()
7.2 $subscribe 和 $onAction
  1. $subscribestate 改变时会调用此函数
const user = useUserStore()

...
user.$subscribe((args, state) => {
  console.log('args, state :>> ', args, state)
},{
  detached: true, // 组件销毁也会监听
  // 与watch类似
  deep: true,
  flush: 'post'
})

在这里插入图片描述

  1. $onAction:调用方法时会调用此函数
// 第二个参数为true时,组件销毁也会监听
// 第二个参数为true时,组件销毁也会监听
// args.after 可以清除一些副作用函数
// args 方法传递的参数
user.$onAction((args) => {
  args.after(() => {
    console.log('after')
  })
  console.log('args :>> ', args)
}, true)

在这里插入图片描述

8. 插件

插件详情

由于有了底层 API 的支持,Pinia store 现在完全支持扩展。以下是你可以扩展的内容:

  • store 添加新的属性
  • 定义 store 时增加新的选项
  • store 增加新的方法
  • 包装现有的方法
  • 改变甚至取消 action
  • 实现副作用,如本地存储
  • 仅应用插件于特定 store

插件是通过 pinia.use() 添加到 pinia 实例的。

import { createPinia } from 'pinia'
import { PiniaPluginContext } from 'pinia'

// 在安装此插件后创建的每个 store 中都会添加一个名为 `secret` 的属性。
// 插件可以保存在不同的文件中
// Pinia 插件是一个函数,可以选择性地返回要添加到 store 的属性。它接收一个可选参数,即 context。
function SecretPiniaPlugin(context: PiniaPluginContext) {
  context.pinia // 用 `createPinia()` 创建的 pinia。 
  context.app // 用 `createApp()` 创建的当前应用(仅 Vue 3)。
  context.store // 该插件想扩展的 store
  context.options // 定义传给 `defineStore()` 的 store 的可选对象。
  // ...
  return { secret: 'the cake is a lie' }
}

const pinia = createPinia()
// 将该插件交给 Pinia
pinia.use(SecretPiniaPlugin)

// 在另一个文件中
const store = useStore()
store.secret // 'the cake is a lie'
案例:持久化插件

mian.ts

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import persistPlugins from '@/store/plugins/persist'
import { Names } from '@/store/store-name'

const app = createApp()
const store = createPinia()

store.use(persistPlugins({
  key: 'wgh',
  include: [Names.USER],	// 默认为空,全部持久化
  storage: sessionStorage  // 默认 localStorage
}))

...
app.mount('#app')

persist.ts

import { PiniaPluginContext } from "pinia";

type Options = {
  key?: string
  storage?: Storage
  include?: string[]
}

// 默认key
const __defaultKey__ = 'wdd'

// 存储数据
const setStorage = (key: string, value: any, storage: Storage): void => {
  storage.setItem(key, JSON.stringify(value))
}

// 获取数据
const getStorage = (key: string, storage: Storage) => {
  const result = storage.getItem(key) ? JSON.parse(storage.getItem(key) as string) : {}
  return result
}

// setup 单个state是ref,所以不能直接使用toRaw
export function toRaws<T extends object>(object: T) {
  const ret: any = Array.isArray(object) ? new Array(object.length) : {}
  for (const key in object) {
    ret[key] = toRaw(object[key])
  }
  return ret
}

// 利用函数柯里化接收用户传参
const persistPlugins = (options: Options) => {
  return (context: PiniaPluginContext) => {
    const { store } = context
    const storage = options?.storage || localStorage
    console.log('storage :>> ', storage);
    const data = getStorage(`${options?.key ?? __defaultKey__}-${store.$id}`, storage)
    store.$subscribe((args, state) => {
      if (!options?.include?.length || options.include?.includes(args.storeId)) {
        setStorage(`${options?.key ?? __defaultKey__}-${store.$id}`, toRaws(store.$state), storage)
      }
    })
    return { 
      ...data
    }
  }
}

export default persistPlugins
Vue3Vue.js的下一个主要版本,它引入了一些功能和改进,以提高性能和开发体验。而TypeScript(TS)是一种强类型的JavaScript扩展,它添加了静态类型检查等功能。Pinia是一个以Composition API为基础的状态管理库,它与Vue3紧密集成在一起。而Vite是一种快速的构建工具,特别适用于Vue3的开发和构建。 在具体实现登录功能时,可以按照以下步骤进行: 1. 首先,需要安装Vue3、TypeScript、PiniaVite。可以通过npm或yarn等包管理工具进行安装。 2. 创建一个新的Vue3项目,并设置使用TypeScript。 3. 在项目的入口文件中引入VuePinia和创建Pinia。 4.Pinia中定义一个用于存储登录信息的状态。 5. 创建一个登录组件,在组件中定义一个表单,用于输入用户名和密码。 6. 在组件中引入定义好的Pinia,并使用`useStore`函数获取存储登录信息的状态。 7. 在组件的`methods`中,编写处理登录功能的方法,验证用户名和密码是否正确。 8. 在组件的模板中,使用v-model指令将输入框与组件内的数据绑定,并绑定登录按钮的点击事件。 9. 在App组件中引入登录组件,并将其渲染到页面上。 10. 运行项目,在浏览器中打开页面,即可看到登录表单。 11. 输入正确的用户名和密码,点击登录按钮,触发登录方法,根据验证结果显示相应的提示信息。 通过以上步骤,可以实现一个基本的登录功能。使用Vue3、TypeScript、PiniaVite可以让开发过程更加高效和可靠。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凡小多

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值