下一代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
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
129 4
|
13天前
|
人工智能 自然语言处理 JavaScript
用 CodeBuddy 搭建Vue框架 像呼吸一样简单
本文介绍如何借助 CodeBuddy 快速创建 Vue 项目。CodeBuddy 是一款支持自然语言编程的工具,能根据用户需求自动生成代码,降低开发门槛。文章详细说明了通过 CodeBuddy 创建 Vue 项目的步骤,包括解决项目创建失败的问题、自动补全代码功能以及启动开发服务器的方法。无论开发者经验如何,CodeBuddy 都能显著提升效率,让开发更专注创意实现。
|
5月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
240 1
|
24天前
|
缓存 JavaScript 前端开发
Vue 基础语法介绍
Vue 基础语法介绍
|
2月前
|
JavaScript 前端开发 算法
vue渲染页面的原理
vue渲染页面的原理
145 56
|
2月前
|
SQL JavaScript 前端开发
Vue实现动态数据透视表(交叉表)
Vue实现动态数据透视表(交叉表)
193 13
|
2月前
|
数据采集 资源调度 JavaScript
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
本文介绍了使用 Vue Flow 绘制流程图的方法与技巧。Vue Flow 是一个灵活强大的工具,适合自定义复杂的流程图。文章从环境要求(Node.js v20+ 和 Vue 3.3+)、基础入门案例、自定义功能(节点与连线的定制、事件处理)到实际案例全面解析其用法。重点强调了 Vue Flow 的高度灵活性,虽然预定义内容较少,但提供了丰富的 API 支持深度定制。同时,文中还分享了关于句柄(handles)的使用方法,以及如何解决官网复杂案例无法运行的问题。最后通过对比 mermaid,总结 Vue Flow 更适合需要高度自定义和复杂需求的场景,并附带多个相关技术博客链接供进一步学习。
|
2月前
|
资源调度 JavaScript 前端开发
Pinia 如何在 Vue 3 项目中进行安装和配置?
Pinia 如何在 Vue 3 项目中进行安装和配置?
183 4
|
3月前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。
|
3月前
|
监控 JavaScript 前端开发
ry-vue-flowable-xg:震撼来袭!这款基于 Vue 和 Flowable 的企业级工程项目管理项目,你绝不能错过
基于 Vue 和 Flowable 的企业级工程项目管理平台,免费开源且高度定制化。它覆盖投标管理、进度控制、财务核算等全流程需求,提供流程设计、部署、监控和任务管理等功能,适用于企业办公、生产制造、金融服务等多个场景,助力企业提升效率与竞争力。
195 12