版本
javascript
"dependencies": {
"pinia": "^3.0.4",
"vue": "^3.5.26"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.3",
"vite": "^7.3.1",
"vite-plugin-vue-devtools": "^8.0.5"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
代码
user.js
javascript
import { defineStore } from 'pinia';
export const useUserStore = defineStore('userStore', {
actions: {
changeUsername(value) {
if(value && value.length<10) {
this.username += value
}
}
},
getters: {
getUsername() {
return this.username.toUpperCase()
}
},
state: () => ({
username: 'abc'
}),
})
App.vue
javascript
<script setup>
import { useUserStore } from '@/store/user'
import { storeToRefs } from 'pinia';
import { ref, toRef, toRefs } from 'vue';
const user = useUserStore()
// 错误
const userInfo = storeToRefs(user)
console.log(userInfo.username)
// 正确
const {username} = storeToRefs(user)
console.log(username)
</script>
<template>
<!-- 错误 -->
<div> {{ userInfo.username }} </div>
<input type="text" v-model="userInfo.username">
<!-- 正确 -->
<div> {{ username }} </div>
<input type="text" v-model="username">
</template>
现象

分析
原因
👉 问题不是出在 storeToRefs,而是出在你"把一个 ref 对象当成普通值来用"的心智模型上 。
[object Object] 说明 input 绑定到的不是字符串,而是一个对象。
关键点:storeToRefs 返回的是什么?
js
const userInfo = storeToRefs(user)
此时:
js
userInfo = {
username: Ref<string>
}
也就是说:
userInfo.username→ 是一个 ref 对象userInfo.username.value→ 才是真正的字符串"abc"
那为什么模板里会出现 [object Object]?
表面看很迷惑,因为你写的是:
vue
<input v-model="userInfo.username">
但 v-model 只能直接绑定:
- 普通变量
- 或单个
ref
❌ 它不擅长绑定「对象里的 ref」
在这种情况下,Vue 会把整个 Ref 当成值塞进 input,于是:
String(Ref) → [object Object]
为什么很多教程让你这样写?
js
const { username } = storeToRefs(user)
因为这样:
js
username === Ref<string>
这是一个干净的 ref ,非常适合 v-model
✅ 正确、推荐写法(重点)
App.vue
vue
<script setup>
import { useUserStore } from '@/store/user'
import { storeToRefs } from 'pinia'
const user = useUserStore()
const { username } = storeToRefs(user)
</script>
<template>
<div>{{ username }}</div>
<input type="text" v-model="username" />
</template>
这和你原来的代码真正的区别
| 你的写法 | 推荐写法 |
|---|---|
userInfo.username |
username |
| 对象里的 ref | 单独的 ref |
v-model 易出坑 |
v-model 官方推荐 |
为什么 {``{ userInfo.username }} 有时"看起来能用"?
因为:
- 插值表达式会自动解包 ref
- 但
v-model在对象嵌套 ref 的场景下不会稳定解包
所以你会看到一个很典型的新手陷阱:
显示正常,但 input 变成
[object Object]
总结一句好记的
storeToRefs之后,一定要解构再用v-model❌
v-model="obj.xxx"✅
const { xxx } = storeToRefs(store)
如果你愿意,我可以顺手帮你把
getteractionv-model + 业务校验
整理成一个标准 Pinia 表单写法模板 👌