四、vue3+ts项目框架搭建——pinia

对比 Vuex优点:

  • Vue2和Vue3都支持,可以定义为选项式和组合式API形式
  • pinia中只有state、getter、action,没有mutations和models
  • pinia中action支持同步和异步,Vuex不支持
  • 良好的Typescript支持,毕竟我们Vue3都推荐使用TS来编写,这个时候使用pinia就非常合适了
  • 无需再创建各个模块嵌套了,Vuex中如果数据过多,我们通常分模块来进行管理,稍显麻烦,而pinia中每个store都是独立的,互相不影响。
  • 体积非常小,只有1KB左右。
  • pinia支持插件来扩展自身功能。
  • 支持服务端渲染

pinia 其中几个API

  1. $patch 可以批量修改 state 里面的数据
  2. $reset 可以重置 state 里面的数据
  3. $subscribe 监听 state 里面的值是否发生了变化:主要做数据持久化,存在本地
  4. $onAction:监听每一个action的执行,并在执行前、执行后、执行出错时执行一些特定的逻辑。

使用

yarn add pinia 
npm install pinia 
----------------------------------
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

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

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

定义store文件

  • 在store文件夹下新建user.js
  • defineStore定义一个store
    • 第一个参数是你的应用中 Store 的唯一 ID
    • 第二个参数可接受两类值:Setup 函数或 Option 对象
    • 仓库最好使用 store 的名字,同时以 use 开头且以 Store 结尾。(比如 useUserStoreuseCartStoreuseProductStore)
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
})

Option Store 类似选项式API

export const useUserStore = defineStore('User', {
  state: () => {
    return {
      count: 0, // 所有这些属性都将自动推断出它们的类型
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2,
    doubleCountPlus() { 
      return this.doubleCount + 1
    },
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

Setup Store 类似组合式API 的 setup 函数

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  function increment() {
    count.value++
  }
  return { count, increment }
})

使用 Store

  • store 是一个用 reactive 包装的对象,所以使用方式和reactive对象一样
<script setup>
import { useUserStore } from '@/store/user' 
const userStore= useUserStore()


// ------------使用变量------
// userStore 是一个用 reactive 包装的对象
let count = userStore.count
// 所以reactive对象的属性不具有响应式,所以不能解构直接使用
// 若想解构,先将它每一个属性转化为响应式,类似roRefs()
import { storeToRefs } from 'pinia'
const { name, doubleCount } = storeToRefs(userStore)


// ----------使用方法---------
userStore.increment() 
//或者解构:actions 的 increment 方法可以直接解构
const { increment } = userStore
increment()
</script>

修改state的三种方法

  • 直接在页面组件中改变数据
  • 使用$patch改变数据
    • patch object:是通过我们熟悉的 $patch 的 对象方式 来变化
    • patch function:也是通过 $patch,但是是通过 函数的方式 来变化
  • direct:通过调用 action 方法(推荐
  • 重置数据
<template>
  <div>baseUrl:{{ baseUrl }}</div>
  <div>ipList:{{ ipList }}</div>
  <button @click="changeData">直接在页面组件中改变数据</button>
  <button @click="changeDataByPatch">使用$patch改变数据</button>
  <button @click="changeDataByAction">使用action改变数据</button>
  <button @click="resetData">重置数据</button>
</template>
 
<script setup>
import useAppStore from "@/store/modules/app"
import { storeToRefs } from "pinia"
const store = useAppStore()
let { baseUrl, ipList } = storeToRefs(store)

/* 第一种修改方式:虽然可以直接修改,但是出于代码结构来说,
*               全局的状态管理还是不要直接在各个组件处随意修改状态,
*               应放于 action 中统一方法修改(piain没有mutation)
*               并不推荐!!!
* */
function changeData() { 
  store.baseUrl = 'https://www.taobao.com/'  
  store.ipList.push('192.168.10.111')  
}

/*第二种修改方式:使用$patch改变数据, $patch 可以同时修改多个值
 *  $patch也有两种的调用方式
 *  第一种写法的在修改数组时,假如我只想修改 ipList 的中第2项 , 也需要传入整个数组, 所以一般都推荐使用第二种传入一个函数的写法
 */
function changeDataByPatch() {
  // 第一种 $patch方法
  store.$patch({
     baseUrl: 'https://www.jd.com/',
     ipList: ['192.168.10.777', '192.168.10.222', '192.168.10.888']
  })

  // 第二种 $patch方法
  store.$patch((state) => {
    state.baseUrl = 'https://www.jd.com/'
    state.ipList[1] = '192.168.10.222'
  })
}

// 第三种修改方式:调用store中的action改变数据的方法changeState
function changeDataByAction() {
  store.changeState('https://www.alibabagroup.com/cn/global/home')  //可以直接给actions里面的方法传递参数
}

// 重置数据
function resetData() {
  store.$reset()
}

</script>

订阅$subscribe:监听 state 里面的值是否发生了变化

cartStore.$subscribe((mutation, state) => {
  console.log(mutation, state)
  // mutation.type //发生改变的三种方式: 'direct' | 'patch object' | 'patch function' 
  // mutation.storeId // store名字
  // mutation.payload // 传递给 cartStore.$patch() 的对象。只有 mutation.type === 'patch object'的情况下才可用
  // 每当状态发生变化时,将整个 state 持久化到本地存储。
  localStorage.setItem('cart', JSON.stringify(state))
})
//subscription 会被绑定到添加它们的组件上 ,当该组件被卸载时,它们将被自动删除。如果想保留,设置 { detached: true } ,以将 state subscription 从当前组件中分离
cartStore.$subscribe(callback, { detached: true })

当前 getter 访问其他 store 的 getter

import { useOtherStore } from './other-store'
export const useStore = defineStore('main', {
  getters: {
    otherGetter(state) {
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

订阅 action $onAction:监听每一个action的执行,并在执行前、执行后、执行出错时执行一些特定的逻辑。

const unsubscribe = someStore.$onAction(
  ({
    name, // action 名称
    store, // store 实例,类似 `someStore`
    args, // 传递给 action 的参数数组
    after, // 在 action 返回或解决后的钩子
    onError, // action 抛出或拒绝的钩子
  }) => {
    // 为这个特定的 action 调用提供一个共享变量
    const startTime = Date.now()
    // 这将在执行 "store "的 action 之前触发。
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // 这将在 action 成功并完全运行后触发。
    // 它等待着任何返回的 promise
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })

    // 如果 action 抛出或返回一个拒绝的 promise,这将触发
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  }
)

// 手动删除监听器
unsubscribe()

// 此订阅器即便在组件卸载之后仍会被保留
someStore.$onAction(callback, true)
  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你好!对于使用 Vue 3、TypeScript 和 Vite 来搭建项目,并结合 Pinia 进行状态管理,你可以按照以下步骤进行操作: 1. 首先,确保你已经安装了 Node.js 和 npm(或者使用 yarn)。 2. 创建一个新的项目文件夹,并进入该文件夹。 3. 在终端中运行以下命令来初始化一个新的 Vue 3 项目: ``` npm init vite@latest ``` 在初始化过程中,选择使用 Vue 3、TypeScript 和默认配置。 4. 进入项目文件夹并安装依赖: ``` cd <project-folder> npm install ``` 5. 接下来,安装 Pinia: ``` npm install pinia ``` 6. 在 `src` 目录下创建一个 `store` 文件夹,并在其中创建名为 `index.ts` 的文件。 7. 在 `index.ts` 中编写你的 Pinia store。例如,你可以创建一个名为 `counter` 的 store,并且在其中定义一个状态和一些操作: ```typescript import { defineStore } from 'pinia'; export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, }), actions: { increment() { this.count++; }, decrement() { this.count--; }, }, }); ``` 8. 在应用的入口文件 `main.ts` 中导入并使用 Pinia: ```typescript import { createApp } from 'vue'; import { createPinia } from 'pinia'; import App from './App.vue'; const app = createApp(App); const pinia = createPinia(); app.use(pinia); app.mount('#app'); ``` 9. 在组件中使用 Pinia store。在你的 Vue 组件中,可以使用 `useStore` 函数来访问 Pinia store: ```typescript import { useCounterStore } from '../store'; export default { setup() { const counterStore = useCounterStore(); return { counterStore, }; }, }; ``` 10. 最后,你可以在组件中使用 `counterStore` 来访问状态和操作: ```vue <template> <div> <p>{{ counterStore.count }}</p> <button @click="counterStore.increment()">Increment</button> <button @click="counterStore.decrement()">Decrement</button> </div> </template> <script> import { useCounterStore } from '../store'; export default { setup() { const counterStore = useCounterStore(); return { counterStore, }; }, }; </script> ``` 这样,你就可以使用 Vue 3、TypeScript、Vite 和 Pinia 搭建一个基本的项目并进行状态管理了。希望对你有帮助!如果还有其他问题,请随时问我。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小曲曲

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

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

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

打赏作者

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

抵扣说明:

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

余额充值