vue3 里面使用 jsx 解构属性,响应式丢失了,怎么处理

2022-12-31 21:54:17 +08:00
 daiwenzh5

如:

const someprops = useAnyHooks();
// someprops 值
const getOne = computed(() => anyvalue);
someprops = {
	one: getOne.value,
}
// 因为存在多个属性,所以直接解构方便一点,但是 one 的响应式好像没了,anyvalue 不会触发更新
return () => (
	<component {...someprops} ></component>
)
// 这样是正常的
return () => (
	<component one={one.value} ></component>
)

这个属性 someprops 里面 one 属性,丢失了响应式,这个怎么处理优雅一点?

5549 次点击
所在节点    Vue.js
78 条回复
shakukansp
2023-01-03 02:00:02 +08:00
我已经问你 把声明从函数里拿到外面 不能触发怎么说了,还在这嘴硬,你说我 35 楼暴露水平,恰恰是暴露了你的水平

至于 2 ,我想法又被你代表了,你上下文我懂,但是你没懂我说的 getter 代表什么,这就是暴露水平
johnkiller
2023-01-03 08:59:25 +08:00
@shakukansp 我从最初的第一个回复就说了,不能放到函数外面。这就是核心的解决方案,函数内触发才能收集依赖。不管什么手段,触发的是原 ref 的 getter 。不要一直纠结在新创建的原生对象上,它就是没有 getter 。

楼主说饿了,我建议让他吃饭。
然后你就跳出来说:“有本事你不让他吃饭试试?”

我在这里所说的 getter ,它就是 Vue 赋予的监听函数,不用神叨叨把我所说的 getter 赋予这里讨论的其它的意义,然后独自窃喜。非要强行全面扩展来解释,那可以出本书了。

还是那句话,你只懂 js ,不懂 Vue 。也就看了几篇文章就窃喜的水平。
johnkiller
2023-01-03 09:06:20 +08:00
@shakukansp 你的逻辑链条也很容易断裂,上下文频繁丢失,思维也收集不到依赖。
daolanfler
2023-01-03 09:23:44 +08:00
johonkiller 说的在理,另一位没看明白在说啥。路过
daiwenzh5
2023-01-03 10:06:37 +08:00
#28 说的正是我的问题所在,使用 reactive 也确实解决了。我之前的代码也是可以运行的,但是太啰嗦了,reactive 使得响应式不用加 value ,直接解构简洁了不少,看起来舒服多了。
那个解决问题就好了,能交流是好事,不要吵架🫰🫰🫰
shakukansp
2023-01-03 10:33:56 +08:00
不说了,楼主再遇到响应式丢失的问题自然会回来翻我在说什么

看不懂我在讲什么的自己开个 sandbox 写写我 21 楼的情况吧

写道函数里面只是治了标,看楼主回复也没懂丢失响应式的本。
shakukansp
2023-01-03 14:31:48 +08:00
https://codesandbox.io/s/vue3-jsx-demo-forked-g06sub?file=/src/components/Demo1.vue

楼主可以先点 2 3 个按钮
然后点第一个
继续点 2 3 个按钮
这是为什么会丢响应式
官网只告诉你为什么不建议解构 reative 对象,没说为什么
这是个初学者常犯的错误
shakukansp
2023-01-03 14:32:27 +08:00
@shakukansp 只告诉你不建议解构响应式对象,没说为什么
shakukansp
2023-01-03 14:34:44 +08:00
同样的使用 toRef 或者 toRefs 等 api 时也要注意这个问题,所以一般传参数的时候我建议用 computed 而不是 toRef 链接一个新的 ref
AllenCai
2023-01-03 15:05:35 +08:00
我觉得两个人说的都对,只是各自角度不同。
还有 demo2 改成 toRefs 会不会就实现 OP 的效果了?只谈实现不谈原理。
<script>
import { defineComponent, ref, toRefs, computed, reactive } from "vue";

function useCounter() {
const number = ref(0);
const count = computed(() => number.value + 1);
return toRefs({
// count 是一个 ref
count,
number,
});
}
export default defineComponent({
setup() {
const counter = useCounter();

return () => {
// 解构 count 为 ref
return <Display {...counter} />;
};
},
});

function Display(props) {
return (
<div>
<button onClick={() => props.number.value++}>inc</button>
<div>{props.count.value}</div>
</div>
);
}
</script>
AllenCai
2023-01-03 15:28:04 +08:00
我先打脸我自己,其实#70 这样写根本就不用 toRefs
看了这么久,其实就是 proxy 的问题
AllenCai
2023-01-03 15:31:23 +08:00
shakukansp 他说的是解构会导致 proxy 对象被解开,触发不了 proxy 里的 getter ,是原因所在。
johnkiller 他说的是将之前的 proxy 引用放在一个新作用域里,所以解构后还是在使用之前的 proxy 引用,实现 OP 的效果,是一种解决办法。
tyx1703
2023-01-03 16:43:39 +08:00
@shakukansp 确实,reactive 包装之后再解构,传到 Display 组件的值是一个新的 number 了,而不是 `useCounter` 中定义的 number.value
liaoliaojun
2023-01-03 18:33:37 +08:00
响应式对象不应该通过 props 传参,用 Provide / Inject 吧
liaoliaojun
2023-01-03 18:47:26 +08:00
liaoliaojun
2023-01-03 18:53:47 +08:00
@liaoliaojun 应该补充一句:可修改的响应式对象不应该通过 props ,只读的是可以的。
shakukansp
2023-01-03 21:37:34 +08:00
@AllenCai 解构赋值并不会丢失响应性

const a = reactive({ b: { c:1 } })

const { b } = a

return { b }

这个时候不论你改 b.c 还是 a.b.c, 渲染到页面上的值都是会同步变化的

只有你主动去切断引用链响应性才会丢失

比如 a. b = { c:2 }
AllenCai
2023-01-04 09:30:24 +08:00
@shakukansp 是的,因为 reactive 的 proxy 化时深层的,所以第一层解开会有第二层的 proxy 在,只有当值为基础类型时,解构赋值会把引用断开

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/905838

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX