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 属性,丢失了响应式,这个怎么处理优雅一点?

5094 次点击
所在节点    Vue.js
78 条回复
shakukansp
2022-12-31 22:10:08 +08:00
??你在说什么

你这是把值赋给了 someprops.one ,又不是把包装对象赋值给 someprops
lalalaqwer
2022-12-31 22:26:30 +08:00
someprops.one = getOne.value
suzic
2022-12-31 22:26:33 +08:00
没试过,试试 torefs
daiwenzh5
2022-12-31 22:32:08 +08:00
@shakukansp #1 对啊,one 只是 someprops 的一个属性,所以才需要解构啊
daiwenzh5
2022-12-31 22:33:14 +08:00
@suzic #3 toRefs 之后所有的属性都是 ref ,解构后就不对了,实际上需要 ref.value 的值
daiwenzh5
2022-12-31 22:36:47 +08:00
@lalalaqwer #2
```ts
// 额, 我上面是顺序写反了,只是例举它的值
export const someprops = {
one: getOne.value,
}

```
shakukansp
2022-12-31 23:16:26 +08:00
@daiwenzh5 我在说你把值给 one ,getOne.value 是值,getOne 是包装对象
这是 js 基础知识而不是响不响应式
const a = { c: 2 }
const b = { a: 1 }
你现在是 b.a = a.c
而不是 b.a = a
引用传递和值传递能分清吗
shakukansp
2022-12-31 23:22:01 +08:00
再举一个比较日常的例子
const a = 1
const b = { c:2 }
const fn = (param) => { if (typeof param === 'number') param + 1 else param.c + 1 }

fn(a)
fn(b)

console.log(a)
console.log(b)
你能搞清楚最后打印出来的分别是多少,那就能明白你这代码里有什么问题
suzic
2023-01-01 10:08:32 +08:00
const comp = () => createVnode(xxx)
setup 里 { comp() }
大概是这样,突然想起来我之前好像也遇到过这种问题
johnkiller
2023-01-01 14:02:55 +08:00
在 render 函数里触发 getter 就行了。
```js
return () => (
const someprops = {
one: getOne.value,
}
return <component {...someprops} ></component>
)
```
johnkiller
2023-01-01 14:05:59 +08:00
再进一步就是封装一个 computed 。

```js
const someprops = computed(() => ({one: xxx.value, two: xxx.value}})
return () => (
return <component {...someprops.value} ></component>
)
```

核心目的是让 value 的 getter 在返回的 render 函数里触发,Vue 才能正常收集依赖。你的写法是在 render 被调用之前就 get 了,当然也就失去了响应式。
johnkiller
2023-01-01 14:06:55 +08:00
#10 #11 的括号有些小问题,将就着看吧。
johnkiller
2023-01-01 14:33:29 +08:00
写了个线上完整的例子,希望能够帮到你:
https://codesandbox.io/s/vue3-jsx-element-plus-forked-n9lvlk?file=/src/App.vue
johnkiller
2023-01-01 14:43:13 +08:00
一楼老兄说明白了 js 值类型,但没明白 vue 的响应式原理。
daiwenzh5
2023-01-02 00:06:42 +08:00
@johnkiller #11 非常感谢你的 demo ,看了你的例子,我发现可能是我描述的不够准确,我希望的是在组件中传递一个 value ,而不是一个 ref ,因此在解构后就丢失了响应式,如:
https://codesandbox.io/s/vue3-jsx-demo-vcjpmo?file=/src/components/Demo1.vue
正如 demo1 ,所有的行为是符合预期的,但是当 hooks 里面返回的 props 存在多个时,手动设置就太麻烦了,所以我希望的时如 demo2 、demo3 那样,在组件中直接解构 props ,但是在这种情况下,响应式就丢失了,我不知道怎么处理更好一点。

具体的代码如下:
```vue
<script>
// demo1
import { defineComponent, ref, computed } from "vue";

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

return () => {
// 传递 count 为 value
return <Display count={count.value} number={number} />;
};
},
});

function Display(props) {
return (
<div>
<button onClick={() => props.number.value++}>inc</button>
<div>{props.count}</div>
</div>
);
}
</script>

```vue
<script>
// demo2
import { defineComponent, ref, computed } from "vue";

function useCounter() {
const number = ref(0);
const count = computed(() => number.value + 1);
return {
// 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}</div>
</div>
);
}
</script>
```
```vue
<script>
// demo3
import { defineComponent, ref, computed } from "vue";

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

return () => {
// 解构 count 是一个 value
return <Display {...counter} />;
};
},
});

function Display(props) {
return (
<div>
<button onClick={() => props.number.value++}>inc</button>
<div>{props.count}</div>
</div>
);
}
</script>
daiwenzh5
2023-01-02 00:15:12 +08:00
@daiwenzh5 #15 感谢每一个愿意给出答复的人,我应该直接上 demo 的,谢罪!
xiaojie668329
2023-01-02 11:46:05 +08:00
直接上一个 codesandbox 呀。
johnkiller
2023-01-02 14:16:02 +08:00
daiwenzh5
2023-01-02 15:26:06 +08:00
@xiaojie668329 嗯嗯,前几楼上了。
前端是野路子出生,没习惯这种在线 demo ,上面有个老哥给了我提醒,前端这种确实方便。
daiwenzh5
2023-01-02 15:33:29 +08:00
@johnkiller 看你的例子应该是解决了我的问题的,现在在车上,等下试试。
vue3 刚开始用,看别人的教程一直用 ref ,说是可以通过编译器提示响应式变量,没怎么用过 reactive 。

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

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

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

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

© 2021 V2EX