下一代vue状态管理工具 pinia,快来看看这个可爱的菠萝吧

简介: 下一代vue状态管理工具 pinia,快来看看这个可爱的菠萝吧

尝试过vuex @4.x的同学都知道,对ts的支持不是很好,写起来不是很方便。不了解的同学请看这篇文章


pinia官网


pinia简单介绍


Pinia是新一代的状态管理器,由 Vue.js团队中成员Phan An所开发的,因此也被认为是下一代的 Vuex,即 Vuex5.x。并被加入官方账户下


Pinia 有如下特点:


  • 支持options api和composition api。


  • 完整的 typescript 的支持。


  • 去除 mutations,只有 state,getters,actions。


  • actions 支持同步和异步。


  • 没有模块嵌套,扁平式的模块组织方式,极大的简化了代码书写过程。


  • 自动代码分割。


  • 支持vue devtools。


安装


npm install pinia
    // yarn add pinia


在vue中注册该库。


import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')


核心概念


pinia从使用角度和vuex几乎一样。通过defineStore来创建一个容器对象。


state


就是以前vuex中的state。类似于组件的data,保存该模块下的数据。


import { defineStore } from 'pinia'
    const useUserStore = defineStore('user', {
      state: () => {
        return {
          name "zh",
          age: 20,
          friends: []
        }
      }
    })


如何获取和修改该state中的数据呢?下面就来介绍一下。


获取state属性


直接导入该模块


<ul>
      <li>姓名: {{ userStore.name }}</li>
      <li>年龄: {{ userStore.age }}</li>
      <li>朋友: {{ userStore.friends }}</li>
    </ul>
   import useUserStore from '../store/userStore'
    const userStore = useUserStore()


看到上面取值这么麻烦,那我来解构看看吧。


<ul>
      <li>姓名: {{ name }}</li>
      <li>年龄: {{ age }}</li>
      <li>朋友: {{ friends }}</li>
    </ul>
    // 不能直接解构,结构后数据将不再是响应式。
    const { name, age, friends } = userStore


貌似上面也能展示,没啥问题,那么我们来尝试改变一下数据,看看界面的变化。


<h1>响应式state数据</h1>
    <ul>
      <li>姓名: {{ userStore.name }}</li>
      <li>年龄: {{ userStore.age }}</li>
      <li>朋友: {{ userStore.friends }}</li>
    </ul>
    <h1>非响应式state数据,通过解构</h1>
    <ul>
      <li>姓名: {{ name }}</li>
      <li>年龄: {{ age }}</li>
      <li>朋友: {{ friends }}</li>
    </ul>
    <button @click="handleUserState">修改数据:handleUserState</button>
    const handleUserState = () => {
      userStore.$patch((state) => {
        state.name = 'llm'
        state.age = 30
        state.friends.push('llm', 'zh')
      })
    }


网络异常,图片无法展示
|


从上面的gif可以看出,基本数据类型是不会做到响应式的,但是引用数据类型可以。(这一问题,通过不同方式修改state,会有不同的效果。因为state返回数据的引用问题。直接修改后,返回的仍旧是原来的对象, 通过$patch和action派发返回的是一个对于原来对象的拷贝。)尽管如此,如果我们想要解构state,那么我们需要使用pinia提供的storeToRefs来为我们服务。


<h1>响应式state数据,通过解构</h1>
    <ul>
      <li>姓名: {{ reactiveName }}</li>
      <li>年龄: {{ reactiveAge }}</li>
      <li>朋友: {{ reactiveFriends }}</li>
    </ul>
    // 将其变为响应式
    const {
      name: reactiveName,
      age: reactiveAge,
      friends: reactiveFriends,
    } = storeToRefs(userStore)


网络异常,图片无法展示
|


修改state属性


  • 直接修改


userStore.name = 'llm'


  • 通过$patch进行批量修改。


  • 可以直接传入一个对象。导入模块获取state值进行修改。


  • 也可以传入一个函数。该函数接收state作为参数。


// 这种方式只有基本数据类型不能响应式
 userStore.$patch((state) => {
    state.name = 'llm'
    state.age = 30
    state.friends.push('llm', 'zh')
  })
  // 这种方式任何数据都不能作为响应式
    userStore.$patch({
        name: 'llm',
        age: 30,
        friends: [...userStore.friends, 'zh', 'llm'],
    })


  • 通过action派发。


// useUserStore.js
    import { defineStore } from 'pinia'
    const useUserStore = defineStore('user', {
      state: () => {
        return {
          name: 'zh',
          age: 20,
          friends: []
        }
      },
      actions: {
        changeState() {
          this.name = 'llm'
          this.age = 30
          this.friends.push('zj', 'llm')
        }
      }
    })


// vue
  userStore.changeState()


这些方式,我依旧是推荐使用action派发,从而做到统一管理。解构state对象时,一定要使用storeToRefsapi。


action


上面已经提到了,就是对state做更新的。和vuex中action一样。但是用法有所改变。 如果管理数据,基本上都是用过action派发函数,利于管理。 下面来看看吧。


基本使用


获取state中的数据直接通过this即可。


// useUserStore.js
    import { defineStore } from 'pinia'
    const useUserStore = defineStore('user', {
      state: () => {
        return {
          name: 'zh',
          age: 20,
          friends: []
        }
      },
      actions: {
        changeState() {
          this.name = 'llm'
          this.age = 30
          this.friends.push('zj', 'llm')
        }
      }
    })


组件中使用直接通过该模块调用action函数即可。


userStore.changeState()


处理异步数据


// 更新异步数据
    getSong() {
      axios({
        url: 'http://123.207.32.32:9001/song/detail?ids=1441758494'
      }).then((res) => {
        console.log('res', res.data.songs[0])
      })
    }


和其他store模块中的action函数使用


其实就是导入其他模块的store,然后直接调用对应的action即可。


import { useAuthStore } from './auth-store'
    export const useSettingsStore = defineStore('settings', {
      state: () => ({
        preferences: null,
        // ...
      }),
      actions: {
        async fetchUserPreferences() {
          const auth = useAuthStore()
          if (auth.isAuthenticated) {
            this.preferences = await fetchPreferences()
          } else {
            throw new Error('User must be authenticated')
          }
        },
      },
    })


getter


用法同vuex中的getter。类似于计算属性,具有缓存功能。利于性能优化。


基本使用


  • getter函数函数中可以使用其他getter。 直接通过this获取即可。


import { defineStore } from 'pinia'
const useUserStore = defineStore('user', {
  // arrow function recommended for full type inference
  state: () => {
    return {
      name: 'zh',
      age: 20,
      friends: [],
      song: {},
      discount: 0.6,
      books: [
        { name: '深入Vuejs', price: 200, count: 3 },
        { name: '深入Webpack', price: 240, count: 5 },
        { name: '深入React', price: 130, count: 1 },
        { name: '深入Node', price: 220, count: 2 }
      ]
    }
  },
  getters: {
    currentDiscount(state) {
      return state.discount * 0.9
    },
    totalPrice(state) {
      let _totalPrice = 0
      for (const book of state.books) {
        _totalPrice += book.count * book.price
      }
      return _totalPrice * this.currentDiscount
    }
  }
})


  • 如果想向getter函数传递参数,我们可以让getter返回一个函数,在外部调用,并传入参数即可。


getters: {
    currentDiscount(state) {
      return state.discount * 0.9
    },
    totalPrice(state) {
      let _totalPrice = 0
      for (const book of state.books) {
        _totalPrice += book.count * book.price
      }
      return _totalPrice * this.currentDiscount
    },
    totalPriceCountGreaterN(state) {
      return function (n) {
        let totalPrice = 0
        for (const book of state.books) {
          if (book.count > n) {
            totalPrice += book.count * book.price
          }
        }
        return totalPrice * this.currentDiscount
      }
    }
  }


// vue
<h1>getters展示</h1>
<div>{{ userStore.totalPrice }}</div>
<div>{{ userStore.totalPriceCountGreaterN(2) }}</div>


网络异常,图片无法展示
|


使用其他store模块的getter


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


注意事项


我们定义getter函数时,可以接受state参数。


  • 如果未接受,并且使用了ts,那么我们需要指定返回值类型。


  • 如果接受了,可以不指定返回值类型。


相关文章
|
1月前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
6天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
1天前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
12 3
|
1月前
|
JavaScript 前端开发 开发者
Vue是如何劫持响应式对象的
Vue是如何劫持响应式对象的
29 1
|
1月前
|
JavaScript 前端开发 API
介绍一下Vue中的响应式原理
介绍一下Vue中的响应式原理
32 1
|
1月前
|
JavaScript 前端开发 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
1月前
|
存储 JavaScript 前端开发
介绍一下Vue的核心功能
介绍一下Vue的核心功能
|
JavaScript 测试技术 容器
Vue2+VueRouter2+webpack 构建项目
1). 安装Node环境和npm包管理工具 检测版本 node -v npm -v 图1.png 2). 安装vue-cli(vue脚手架) npm install -g vue-cli --registry=https://registry.
1065 0
|
1月前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
1月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
39 1
vue学习第一章