4、Vue 3 Pinia 使用实录:多种方式使用 State

作者: 温新

图书: 【Vue 3 Pinia 使用实录】

阅读: 179

时间: 2024-09-08 02:10:23

嗨,我是温新

为了保证文章的独立性,本篇文章把上篇文章的数据仓库拿来使用。

定义数据仓库

src/stores/user.ts

// 1、导入创建 store 的 defineStore 函数
import { defineStore } from "pinia";
import { ref } from "vue";

// 2、创建名为 user 的 store
const useUserStore = defineStore('user', () => {
    // 2.1、定义全局响应式数据
    const username = ref("王美丽")
    const age = ref(18)

    // 2.2、定义全局更新数据人函数
    const updateUsername = (uname:string) => {
        username.value = uname
    }

    const updateAge = (uage:number) => {
        age.value = uage
    }

    // 2.3、返回一个对象,暴露可对外使用的数据
    return {
        username,
        age,
        updateUsername,
        updateAge
    }
})

// 3、到处 store
export default useUserStore

多种方式使用 state

方式一:基础使用

src/App.vue

<template>
    <h3>Vue 3 Pinia 使用实录</h3>
    <div class="main">
        <!-- 3、使用用户仓库中用户的数据 -->
        <h3>{{ userStore.username }}</h3>
        <h3>{{ userStore.age }}</h3>
        <button @click="updateUsername">修改名称</button>
        <button @click="updateUserage">修改年龄</button>
    </div>
</template>

<script setup lang="ts">
    // 1、导入用户数据仓库
    import  useUserStore  from "@/stores/user.ts";

    // 2、实例化 userStore,使页面能够访问到用户数据仓库中的状态和方法
    const userStore = useUserStore()

    // 3、使用用户数据仓库的函数
    const updateUsername = () => {
    	userStore.updateUsername("王丽丽")
    }
    const updateUserage = () => {
    	userStore.updateAge(19)
    }

</script>

<style scoped>
    .main {
    	background-color: pink;
    }
</style>

方式二:解构赋值

src/App.vue

<template>
  <h3>Vue 3 Pinia 使用实录</h3>
  <div class="main">
      <h3>{{ username }}</h3>
      <h3>{{ age }}</h3>
      <button @click="updateByUsername">修改名称</button>
      <button @click="updateUserage">修改年龄</button>
  </div>
</template>

<script setup lang="ts">
	import  useUserStore  from "@/stores/user.ts";
	 // 1、 引入 Pinia 提供的 storeToRefs 函数,用于将 store 中的 state 转换为 ref 对象
	import { storeToRefs } from 'pinia'

	const userStore = useUserStore()
	// 2、使用 storeToRefs 将 store 中的 state 属性(username 和 age)转换为 ref 对象
	const { username, age } = storeToRefs(userStore)
	// 3、直接从 userStore 解构出更新用户名和年龄的方法
	const { updateUsername, updateAge } = userStore;
 
	const updateByUsername = () => {
		updateUsername("王丽丽")
	}
	const updateUserage = () => {
		updateAge(19)
	}
</script>

<style scoped>
.main {
  background-color: pink;
}
</style>

多组件使用 state

使用 pinia 的一个重要原因就是组件间的数据共享,现在通过多组件来使用 state 数据。

1、创建子组件并使用仓库数据

src/components/User.vue

<template>
    <div class="user">
        <h1>{{ username }}</h1>
        <h1>{{  age }}</h1>
    </div>
</template>

<script setup lang="ts">
	import  useUserStore  from "@/stores/user.ts";
	import { storeToRefs } from 'pinia'
	import User from './components/User.vue'

	const userStore = useUserStore()
	const { username, age } = storeToRefs(userStore)
</script>

<style scoped>
    .user {
        background-color: orange;
    }
</style>
2、父组件中使用子组件

src/App.vue

<template>
  <h3>Vue 3 Pinia 使用实录</h3>
  <div class="main">
      <h3>{{ username }}</h3>
      <h3>{{ age }}</h3>
      <button @click="updateByUsername">修改名称</button>
      <button @click="updateUserage">修改年龄</button>
  </div>
  
  <!-- 使用子组件 -->
  <User />
</template>

<script setup lang="ts">
	import  useUserStore  from "@/stores/user.ts";
	import { storeToRefs } from 'pinia'

	import User from './components/User.vue'

	const userStore = useUserStore()
	const { username, age } = storeToRefs(userStore)
	const { updateUsername, updateAge } = userStore;
 
	const updateByUsername = () => {
		updateUsername("王丽丽")
	}
	const updateUserage = () => {
		updateAge(19)
	}
</script>

<style scoped>
.main {
  background-color: pink;
}
</style>
3、测试

浏览器中输入 http://localhost:5173/ 可以看到两个区块的结果。

  • 父组件中,点击 “修改名称”,会发现子组件中使用的数据也跟着发生了变化。

批量修改数据

批量修改数据,使用 store 中的 $patch 方法。

修改模板,增加批量操作点击事件

src/App.vue

<template>
  <h3>Vue 3 Pinia 使用实录</h3>
  <div class="main">
		...
      	<button @click="changePatchStore">批量修改数据</button>
  </div>
  
  <User />
</template>
方式一:使用 $patch 批量修改

src/App.vue

...

<script setup lang="ts">
	...
    
	const changePatchStore = () => {
		userStore.$patch({
			username:"王美美",
			age:19
		})
	}
</script>
方式二:使用 state 参数修改

src/App.vue

...

<script setup lang="ts">
	...
    
	const changePatchStore = () => {
		userStore.$patch( state => {
			state.username = "王美美"
			state.age = 19
		})
	}
</script>
方式三:批量替换

pinna 中提供了 $state 方法替换整个 state 对象

src/App.vue

...

<script setup lang="ts">
	...
    
	const changePatchStore = () => {
		// 方式一
		userStore.$state = {
			username:"王美丽丽",
			age:19
		}

		// 方式二
		// userStore.$patch({
		// 	username:"美美丽丽",
		// 	age:19
		// })
	}
</script>

重置 state

修改了 state 数据后,想要还原到旧数据时,可以使用 store$reset() 方法。

注意:按照文档说明案例,使用选项式 API 时不会出现问题,但是在使用组合式 API 时会存在问题。下面使用组合式 API 进行学习,并解决组合式 API 中 $reset 报错问题。

添加重置事件

src/App.vue

<template>
  <h3>Vue 3 Pinia 使用实录</h3>
  <div class="main">
		...
	 
      	<button @click="handleReset">重置</button>
  </div>
  
  <User />
</template>
实现重置 state
...

const handleReset = () => {
    userStore.$reset()
}

当点击重置按钮时,组合式 API 中 $reset 报错信息如下:

runtime-core.esm-bundler.js:221 Uncaught Error:: Store "user" is built using the setup syntax and does not implement $reset().

解决组合式 API 重置报错

main.ts

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

import { createPinia } from 'pinia'
const pinia = createPinia()

// 解决 $reset 重置报错
pinia.use(({store}) => {
    // 获取原始值
    const initialState = JSON.parse(JSON.stringify(store.$state))
    store.$reset = () => {
        // 重置原始使用
        store.$state = JSON.parse(JSON.stringify(initialState))
    }
})
const app = createApp(App)
app.use(pinia)

app.mount('#app')
测试效果
  • 先点击 “批量修改数据按钮”
  • 再点击 “重置” 按钮

订阅状态

通过 store 的 $subscribe() 方法查看状态及其变化。与常规的 watch() 相比,使用 $subscribe() 的优点是 *subscriptions* 只会在 *patches* 之后触发一次。

src/App.vue

...

<script>
	...
    
    import { watch } from 'vue'

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

    watch(userStore.$state, (newValue, oldValue) => {
    	console.log(newValue, oldValue)
    }) 
</script>

1、点击 修改名称 按钮,控制台中观察$subscribewatch 的变化;

2、再次点击 修改名称 按钮,观察两者的变化。

关于 state 的相关操作就结束了。

请登录后再评论