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 他模板中渲染的仍然还是之前的对象。 这是为什么

  1. 应该不会有这种 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下面这种结构
Vue3整合Pinia,懂行的大佬进来帮忙看下,为什么 重新在将store的属性设置为 reactive({})不生效?

如果执行 代码 person.value = {} 会出现什么现象?
我的理解: person是RefImpl, 将他的value指向一个空对象,不再是之前的响应式代理对象。

实际现象:如下图,value还是一个响应式代理对象,只不过这个Proxy代理对象的target目标对象是空对象
Vue3整合Pinia,懂行的大佬进来帮忙看下,为什么 重新在将store的属性设置为 reactive({})不生效?

问题: 这是为什么?怎么做到的? 有相关的参考资料或者源码么?


回答:

如果想要直接替换整个对象的话,应该使用 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

回到顶部