使用 pinia 时,解构 store 里的 helloWorld 和 count 时,没有发生响应式数据变化的情况。这是因为在使用 store 的过程中,如果直接进行进行解构的话,会破坏数据的响应,因此可以通过使用 storeToRefs 来解构。
一、pinia 的使用时的问题复现
1、stores:counter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { defineStore } from "pinia";
export const mainStore = defineStore("main", { state: () => { return { helloWorld: "hello world !!!", count: 0, }; }, getters: {}, actions: {}, });
|
2、组件:Test.vue
1 2 3 4 5 6
| <template> <div>{{ helloWorld }}{{ count }}</div> </template>
|
如果不使用storeToRefs,点击按钮不会生效。
storeToRefs的源码中,会先进行vue版本的判断,如果是Vue2版本,会直接返回toRefs(store),非Vue2环境,遍历对象的键值,会过滤掉store中的非ref/reactive对象,对于符合ref和reactive类型的值,将其复制到一个新的对象中refs中,最后返回refs
1 2 3 4 5 6
| <script setup> import {storeToRefs} from "pinia" import {mainStore} from'../stores/counter' const store = mainStore() const {(helloWorld, count)} = storeToRefs(store) </script>
|
1 2 3
| <template> <div><button @click="handleClick">Add</button></div> </template>
|
1 2 3 4 5
| <script setup> import {mainStore} from '../stores/counter' const store = mainStore() const handleClick = () => {store.count++} </script>
|
4、App.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <template> <header> <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" /> <div class="wrapper"> <Test></Test> <add-button></add-button> </div> </header> <RouterView /> </template>
|
1 2 3 4 5
| <script setup> import {(RouterLink, RouterView)} from 'vue-router' import Test from './components/Test.vue' import AddButton from "./components/AddButton.vue" </script>
|
二、pinia如何修改状态数据
1、$patch修改单个或者多个数据
1
| <div><button @click="handleClickPatch">Add handleClickPatch</button></div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <script setup> import { mainStore } from '../stores/counter'; const store = mainStore() const handleClick = () => { store.count++; }
const handleClickPatch = () => { store.$patch({ count:store.count + 2, helloWorld:store.helloWorld === 'yq' ? 'HelloWorld' : 'yq' }) } </script>
|
2、$patch加函数形式修改状态数据
适合修改复杂数据,例如数组、对象
1
| <div><button @click="handleClickMethod">Add handleClickMethod</button></div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <script setup> import { mainStore } from '../stores/counter'; const store = mainStore() const handleClick = () => { store.count++; }
const handleClickPatch = () => { store.$patch({ count:store.count + 2, helloWorld:store.helloWorld === 'yq' ? 'HelloWorld' : 'yq' }) }
const handleClickMethod = () =>{ store.$patch((state) => { state.count++; state.helloWorld = state.helloWorld === 'yq' ? 'helloworld' :'yq' }) } </script>
|
3、actions
在使用actions的时候,不能使用箭头函数,因为箭头函数绑定的是外部的this
stores :counter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| export const mainStore = defineStore('main', { state:()=>{ return { helloWorld:'hello world !!!', count:0 } }, getters:{
}, actions:{ changeState(){ this.count++ this.helloWorld = 'yq' } } })
|
组件:AddButton.vue
1
| <div><button @click="handleClickAction"> Add handleClickAction</button></div>
|
1 2 3
| const handleClickAction = () =>{ store.changeState() }
|
4、getters
store:counter.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| export const mainStore = defineStore('main', { state:()=>{ return { helloWorld:'hello world !!!', count:0, phone:'19542932249' } }, getters:{ phoneHidden(state){ console.log("go 具有缓存 只会调用一次") return state.phone.toString().replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2') } }, actions:{ changeState(){ this.count++ this.helloWorld = 'yq' } } })
|
注意:getters里是可以使用this的
写法如下:
1 2 3 4 5 6 7
| getters:{ phoneHidden():String{ console.log("go 具有缓存 只会调用一次") } },
|
组件:Test.vue
1 2 3 4 5 6 7 8
| <template> <div> {{ store.helloWorld}}{{store.count}} </div> <div> {{ phoneHidden }} </div> </template>
|
1 2 3 4 5 6
| <script setup> import { storeToRefs } from "pinia"; import { mainStore } from '../stores/counter'; const store = mainStore() const { helloWorld,count,phoneHidden } = storeToRefs(store) </script>
|
组件:AddButton.vue
1
| <div><button @click="handleClickChangePhone">change phone</button></div>
|
1 2 3 4 5 6 7 8
| <script setup> import { mainStore } from '../stores/counter'; const store = mainStore()
const handleClickChangePhone = () => { store.phone = "18775352722" } </script>
|
5、Github项目代码:
github: https://github.com/HeyJudeYQ/pinia-demo