Vue3整合Pinia,懂行的大佬进来帮忙看下,为什么 重新在将store的属性设置为 reactive({})不生效?
本来是向搞个在线项目 方便大家大家理解,但是试了几个云ide平台都太卡了,不好用就没搞。
问题
需求场景是这样的 有一个pinia Store(studentStore),这个store内部定义了一个
let address = reactive({}) . 然后 有一个方法 resetAddress 方法会重新将 address变量指向另外一个新的响应式代理对象。
export const useStudentStore = defineStore('student', () => { //只会被执行一次
console.log("studentStore的defineStore函数执行")
const name = ref("zhangsan")
let address = reactive({})
let studentInfo = reactive({})
const changeCity = function (city) {
address.city = city
}
const resetAddress = function () {
//注意这里将 address 指向一个新的响应式代理对象
address = reactive({})
}
const resetStudentInfo = function () {
studentInfo = reactive({})
}
return {
name,
address,
studentInfo,
resetStudentInfo,
changeCity,
resetAddress,
}
})
在组件A中 执行 useStudentStore 函数得到studentStore. 然后 在组件A中显示studentStore的address属性。
组件A中有一个按钮,这个按钮随机生成 字符串1 和字符串2, 他们分别作为 属性名和属性值 被添加到address身上。 这个按钮还会生成一个随机数字,数字大于17的时候就会 调用resetAddress方法。
我们看到的效果就是 点击按钮---》addres新增了一个属性---》再次点击---》再次新增一个属性---》突然某次生成的随机数大于17,执行resetAddress方法。
resetAddres方法内部会将 defineStoree函数的第二个参数函数中的 address 指向一个新的响应式代理对象, 这个新的响应式代理对象显然没有任何属性。 对于组件A 他模板中渲染的仍然还是之前的对象。 这是为什么
<template> <div>
<div>这是TestPinia.vue</div>
{{ studentStore.name }}
<div>address: {{ studentStore.address }}</div>
<div>studentInfo: {{ studentStore.studentInfo }}</div>
<el-button @click="handleClick">点击</el-button>
</div>
</template>
<script setup>
import {useStudentStore} from '@/store/student.js'
import {ref, reactive, onMounted, inject, toRef, toRefs} from "vue";
import {storeToRefs} from "pinia";
import Constants from "@assets/js/Constants.js";
const $utils = inject(Constants.$utilsSymbol);
const studentStore = useStudentStore();
// const {
// name,
// address,
// studentInfo
// } = storeToRefs(studentStore);
const {changeCity, resetCity, resetStudentInfo} = studentStore;
function handleClick() {
let propName = $utils.randomString(5);
let propvalue = $utils.randomString(3);
studentStore.address[propName] = propvalue;
let random = $utils.GetRandomNum(10, 20);
if (random > 17) {
console.log("resetCity");
resetCity();
}
}
</script>
问题
1 . resetAddres方法内部会将 defineStoree函数的第二个参数函数中的 address 指向一个新的响应式代理对象, 这个新的响应式代理对象显然没有任何属性。 对于组件A 他模板中渲染的仍然还是之前的对象。 这是为什么
- 应该不会有这种 resetAddress内部 重新将 address指向一个新的响应式代理对象的需求吧? 我之所以会这样写 是因为 有一种场景: 把后端返回的一个对象放置到store的addres中,但是不知道 返回的这个对象有哪些属性。 所以我无法通过address.xxPropName的形式给address设置值 ,而是用了 Object.assign(后端返回对象, address)。 在需要清空address对象的时候 就写出了这种 resetAddress的代码。
问题有描述清除么?
补充问题
我还有一个地方不明白。
const person = ref({ name: "zhangsan",
age: 12,
})
console.log("person", person)
ref的是一个对象,等价于这个对象 先 reactive( {} )得到一个响应式代理对象Proxy,然后RefImpl对象的value等于这个响应式代理对象. 就是i下面这种结构
如果执行 代码 person.value = {}
会出现什么现象?
我的理解: person是RefImpl, 将他的value指向一个空对象,不再是之前的响应式代理对象。
实际现象:如下图,value还是一个响应式代理对象,只不过这个Proxy代理对象的target目标对象是空对象
问题: 这是为什么?怎么做到的? 有相关的参考资料或者源码么?
回答:
如果想要直接替换整个对象的话,应该使用 ref
而不是 reactive
,具体可查看官方文档reactive() 的局限性中的描述
不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用。这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:
let state = reactive({ count: 0 })
// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 })
正确写法如下:
const address = ref({});function resetAddress() {
address.value = {};
}
回答:
因为 address
变量本质上是个指针,重新赋值的行为把该指针指向了别的内容,自此其与原内容完全不相干。
let a = 100;const b = {
__a: a
};
console.log(b.__a);
a = 1000;
console.log(b.__a); // ?
以上是 Vue3整合Pinia,懂行的大佬进来帮忙看下,为什么 重新在将store的属性设置为 reactive({})不生效? 的全部内容, 来源链接: utcz.com/p/934929.html