学完 Pinia 真香,不想用 vuex 了

💕Pinia 注册

✔ vue3 与 Pinia 注册

javascript 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp()

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

✔ vue2 与 Pinia 注册

javascript 复制代码
import Vue from 'vue'
import App from './App.vue'
import { createPinia, PiniaVuePlugin } from 'pinia'

Vue.use(PiniaVuePlugin)

new Vue({
  render: (h) => h(App),
  createPinia()
}).$mount('#app');

💕定义与使用 Store

✔ 定义 Store

javascript 复制代码
import { defineStore } from 'pinia'

// 第一个参数是应用程序中 store 的唯一 id
export const useUser = defineStore('user', {
    state: () => {
        return { name: 'Jack', age: 18 }
    },
    getters: {},
    actions: {}
})

✔ 在 vue3 <script setup>中使用

vue 复制代码
<script setup>
import { useUser } from '@/stores/User'
const user = useUser()    
</script>
<template>
    <div>{{ user.name }} - {{ user.age }}</div>
</template>

✔ 在 vue3 setup() 中使用

vue 复制代码
<script>
import { useUser } from '@/stores/User'
export default {
    setup() {
        const user = useUser()
        
        return {
            user
        }
    }
}
</script>
<template>
    <div>{{ user.name }} - {{ user.age }}</div>
</template>

✔ 在 vue2 中使用

  1. 导入可读属性,无法修改
vue 复制代码
<script>
import { useUser } from '@/stores/User'
import { mapState } from 'pinia'
// 导入的是只读属性,无法进行修改    
export default {
    computed: {
        ...mapState(useUser, {
            user: (store) => store,
            // 自定义属性
            ownName: 'age'
            double: (store) => store.age * 2,
            // 通过 this 读取自定义属性值
            magicValue: (store) => {
               return this.double + store.age + this.ownName
           }
        })
        // 也可以采用这种方式
        // ...mapState(useUser, ['age', 'name'])
        // <div>{{ name }} - {{ age }}</div>
    }
}
</script>
<template>
    <button @click="age = 12">尝试修改 age</button>
    <div>{{ user.name }} - {{ user.age }}</div>
</template>
  1. 导入可读可修改属性
vue 复制代码
<script>
import { useUser } from '@/stores/User'
import { mapWritableState } from 'pinia'
// 导入的是可修改属性    
export default {
    computed: {
        ...mapWritableState(useUser, {
            user: (store) => store
        })
    }
}
</script>
<template>
    <div>{{ user.name }} - {{ user.age }}</div>
</template>

✔ 使用效果

💕修改 Store

✔ 直接修改 store

vue 复制代码
<script setup>
import { useUser } from '@/stores/user'

const user = useUser() // user 是 reactive 对象

// 不能使用 { age, name } = user 进行解绑,具体看注意事项

const handle = () => {
    // 直接修改
    user.age++
}
</script>
<template>
    <div>{{ user.age }} - {{ user.name }}</div>
</template>

✔ 通过 $patch 修改 store

  1. 接收变量的方式
vue 复制代码
<script setup>
import { useUser } from '@/stores/user'

const user = useUser()

const handle = () => {
    user.$patch({
        name: 'John',
        age: 81
    })
}
</script>
<template>
    <button @click="handle">修改 user 信息</button>
    <div>{{ user.age }} - {{ user.name }}</div>
</template>
  1. 接收函数的方式
vue 复制代码
<script setup>
import { useUser } from '@/stores/user'

const user = useUser()

const handle = () => {
    user.$patch((state) => {
        // 直接对 state 进行修改
        state.age = 81
        state.name = 'John'
    })
}
</script>
<template>
    <button @click="handle">修改 user 信息</button>
    <div>{{ user.age }} - {{ user.name }}</div>
</template>

✔ 重置 state

javascript 复制代码
import { useUser } from '@/stores/user'

const user = useUser()

// 重置 (初始状态)
user.$reset()

✔ 替换 state

javascript 复制代码
import { useUser } from '@/stores/user'

const user = useUser()

store.$state = { name: 'Paimon', age: 12 }

💕 订阅 Store

可以通过 $subscribestore 进行订阅。只会在 patches 之后触发一次

javascript 复制代码
import { useUser } from '@/stores/user'
const user = useUser()

user.$subscribe((mutation, state) => {
  console.log(mutation)
  console.log(state)
})

mutation.typepatch object

javascript 复制代码
user.$patch({ name: 'John', age: '81' })

mutation.typepatch function

javascript 复制代码
user.$patch((state) => {
    state.name = 'John'
    state.age = '81'
})

mutation.typedirect

javascript 复制代码
user.name = 'John'
user.age = '81'

💕 定义与使用 Getters

✔ 定义 Getters

javascript 复制代码
import { defineStore } from 'pinia'
import { useOtherStore } from '@/store/otherStore'

// 第一个参数是应用程序中 store 的唯一 id
export const useUser = defineStore('user', {
    state: () => {
        return { name: 'Jack', age: 18 }
    },
    getters: {
        // 访问 state 的值
        doubuleAge: (state) => state.age * 2,
        // 访问 getters 的值(通过 this 进行访问)
        doubleAgePlusOne: (state) => this.doubleAge + 1
        // 访问其他 store 的 getters
        otherstore: () => {
             const otherStore = useOtherStore()
             return state.other
        }
    },
    actions: {}
})

✔ 访问 Getters

vue 复制代码
<script setup>
import { useUser } from '@/stores/User'
const user = useUser()    
</script>
<template>
    <div>{{ user.name }} - {{ user.age }} - {{ user.doubuleAge }} - {{ user.doubuleAgePlusOne }}</div>
</template>

💕 定义与使用 Actions

✔ 定义 Actions

非常适合定义业务逻辑

javascript 复制代码
import { defineStore } from 'pinia'
import { useOtherStore } from '@/store/otherStore'
// 第一个参数是应用程序中 store 的唯一 id
export const useUser = defineStore('user', {
    state: () => {
        return { name: 'Jack', age: 18 }
    },
    getters: {},
    actions: {
        // 封装业务逻辑
        async registerUser({ name, password }) {
            const data = await api.post({ login, password })
            this.state.name = data.name
            this.state.age = data.age
        }
        // 访问其他的 store
        async fetchUserPreferences() {
           const other = useOtherStore()
           // 获取到 other 的数据
        }
    }
})

actions 可以是异步的 ,您可以在其中await 任何 API 调用甚至其他操作!

✔ 访问 Actions

javascript 复制代码
import { useUser } from '@/store/user'
const user = useUSer()

// vue3 的方法方式,vue2 的访问方式见注意事项
user.registerUser({
    name: 'john'
    password: '123'
})

💕 定阅 Actions

可以使用 store.$onAction() 订阅 actions 及其结果

javascript 复制代码
const userStore = useUSer()
const unsubscribe = userStore.$onAction(
  ({
    name, // action 的名字
    store, // store 实例
    args, // 调用这个 action 的参数
    after, // 在这个 action 执行完毕之后,执行这个函数
    onError, // 在这个 action 抛出异常的时候,执行这个函数
  }) => {
    // 记录开始的时间变量
    const startTime = Date.now()
    // 这将在 `store` 上的操作执行之前触发
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

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

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

// 手动移除订阅
unsubscribe()

💕 Pinia 持久化配置

需要借助 pinia-plugin-persistedstate

javascript 复制代码
import App from './App.vue'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate  from 'pinia-plugin-persistedstate'

const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

app.use(pinia)
javascript 复制代码
// 组合式写法 具体看 注意事项
import { defineStore } from 'pinia'
const persist = {
    key: 'storeKey',
    storage: window.sessionStorage,
    // 部分持久化状态的点符号路径数组,[]意味着没有状态被持久化(默认为undefined,持久化整个状态)
    // paths: ['age']
}
export const useUser = defineStore('user', () => {
  const name = ref('Jack')
  const age = ref(18)
  const session = JSON.parse(window.sessionStorage.getItem('storeKey'))
  if (session) { // 判断 session 是否已经有值存在,实现持久化
    name.value = session.name
    age.value = session.age
  }
  return {
    name, age
  }
}, { persist })

💕 注意事项

✔ 选项式与组合式写法

javascript 复制代码
// 选项式
import { defineStore } from 'pinia'
export const useUser = defineStore('user', {
  state: () => {
    return {
      name: 'Jack',
      age: 18
    }
  },
  getters: {
    doubuleAge: (state) => state.age * 2,
    doubleAgePlusOne: (state) => this.doubleAge + 1
  },
  actions: {
      async registerUser() {/*.......*/}
  }
})

等价于:

javascript 复制代码
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useUser = defineStore('user', () => {
    // state
    const name = ref('Jack')
    const age = ref(18)
    
    // getters
    const doubuleAge = ref()
    doubuleAge.value = age.value * 2
    const doubleAgePlusOne = ref()
    doubleAgePlusOne.value = doubuleAge.value + 1
    
    // actions
    const registerUser = () => { /*.......*/ }
    
    return {
        name,
        age,
        doubuleAge,
        doubleAgePlusOne,
        registerUser
    }
})

✔ 解构失去响应式

vue 复制代码
<script setup>
import { useUser } from '@/stores/user'
const user = useUser()

// user 是 reactive 对象

let { age, name } = user // 解构失去了响应式,不解构是不会失去响应式的

const handle = () => {
  age++ // 修改值
  console.log(age) // 修改后
}
</script>
<template>
    <button @click="handle">尝试修改 age</button>
    <div>{{ name }} - {{ age }}</div>
</template>

解决办法:使用 storeToRefs ,它将为任何响应式属性创建 refs

javascript 复制代码
import { storeToRefs } from 'pinia'
import { useUser } from '@/stores/user'
const user = useUser()
let { age, name } = storeToRefs(user) // 有了响应式

const handle = () => {
  age.value = age.value + 1 // 注意
}

✔ 取消订阅 Store

默认情况下,state subscriptions 绑定到添加它们的组件。当组件被卸载时,它们将被自动删除。如果要在卸载组件后保留它们,可以进行以下操作:

vue 复制代码
<script setup>
import { useUser } from '@/stores/user'
const user = useUser()

// 此订阅将在组件卸载后保留
user.$subscribe((mutation, state) => {
  console.log(mutation)
  console.log(state)
}, { detached: true })
</script>

✔ 取消订阅 Actions

默认情况下,action subscriptions 绑定到添加它们的组件。当组件被卸载时,它们将被自动删除。如果要在卸载组件后保留它们,可以进行以下操作:

javascript 复制代码
<script setup>
import { useUser } from '@/stores/user'
const user = useUser()

// 此订阅将在组件卸载后保留
user.$onAction(() => {/* ..... */}, true)
</script>

✔ vue2 将 Actions 印射到组件

javascript 复制代码
import { mapActions } from 'pinia'
import { useUser } from '@/stores/user'
export default {
  methods: {
    ...mapActions(useUser, ['registerUser'])
    ...mapActions(useUser, { myOwnName: 'registerUser' }),
  },
}

✔ 如何监听整个 Pinia 状态

javascript 复制代码
import { createApp, watch } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp()

watch(pinia.state, (state) => {
  // 每当它发生变化时,将整个状态持久化到本地存储
  localStorage.setItem('piniaState', JSON.stringify(state))
},{ deep: true })

app.use(pinia)
app.mount('#app')
相关推荐
Martin -Tang12 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发13 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁1 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂1 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐2 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成4 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽4 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新5 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html
秦jh_6 小时前
【Linux】多线程(概念,控制)
linux·运维·前端