1. 首页
  2. Vuejs

为什么 Vue3 的 ref 让很多大佬操碎了心?

最近 Vue3 关于 ref-sugar 的提案引起了广泛的讨论: juejin.im/post/689417…


<script setup> import Foo from './Foo.vue' // declaring a variable that compiles to a ref ref: count = 1 const inc = () => { count++ } // access the raw ref object by prefixing with $ console.log($count.value) </script> <template> <Foo :count="count" @click="inc" /> </template>

感兴趣的同学可以先阅读上面的讨论,本文不再重复讨论。 提案目的是将 ref.value 的写法进一步简化,但因为修改了 js 语言本身的语义,引起了很多的争论。

本文希望用一种最保守的思路提供另一种心智负担可能更小的解决方案

1. 回顾 vue-composition-api-rfc

读写 ref 的操作比普通值的更冗余,因为需要访问 .value。尤大大对使用编译时的语法糖来解决这个问题非常谨慎,曾明确表示不默认提供此类支持。 vue-composition-api-rfc.netlify.app/zh/#%E5%BC%…

为什么 Vue3 的 ref 让很多大佬操碎了心?

对此我非常赞同。

但在 js 中必须要加 .value ,在模板中又不需要加 .value,这无疑造成了一定程度的混乱和割裂感。

2. 解决思路:转成对象 new String(‘foo’) 再拦截

为什么会这样?究其根本,我们无法对基础数据类型值做拦截。行呀,那我们把基础数据类型转成对应的包装类实例,再进行拦截。 例如: let str = 'foo' 改写成 let strObj = new String('foo'),此时 strObj 是对象,接下来我们尝试拦截,我写了一个库re-primitive,使用示例如下:

 js
const { rePrimitive, watchEffect } = require('../dist/re-primitive.cjs')

// 用 rePrimitive 代替 ref; 并传入String的包装对象  new String('foo')
let proxy = rePrimitive(new String('foo'))
// let proxy = rePrimitive('foo')  // 内部做了装箱,可简写去掉 new String()
// rePrimitive 的作用是将对象设置成响应式,并增加 setValue() 修改数据的方法

watchEffect(() => {
  console.log('输出 proxy instanceof String:', proxy instanceof String) // true , 可以看出 proxy是String的实例,可以使用所有的String的原型方法
  console.log('输出 proxy.valueOf():' + proxy.valueOf())
  console.log('输出:proxy.substring(1): ' + proxy.substring(1))
})
console.log('==========')
proxy.setValue('bar') // 响应式修改数据,重新执行 effect 函数

// 输出结果

// 输出 proxy instanceof String: true
// 输出 proxy.valueOf():foo
// 输出:proxy.substring(1): oo
// ==========
// 输出 proxy instanceof String: true
// 输出 proxy.valueOf():bar
// 输出:proxy.substring(1): ar


  • rePrimitive: 相当于 reactive, ref。将基本数据类型设置成响应式,如果传递的是 new String(‘foo’), 则 proxy 仍然是 String 的实例; 支持 String | Number | Boolean 三种类型,可简写去掉主动装箱。
 js
let proxyStr = rePrimitive('foo') // 等价于 let proxyStr = rePrimitive(new String('foo'))
let proxyNum = rePrimitive(123) // 等价于 let proxyNum = rePrimitive(new Number(123))
let proxyBool = rePrimitive(false) // 等价于 let proxyBool = rePrimitive(new Boolean(false))


为什么 Vue3 的 ref 让很多大佬操碎了心? 为什么 Vue3 的 ref 让很多大佬操碎了心? 为什么 Vue3 的 ref 让很多大佬操碎了心?

  • setValue: 响应式修改数据,重新执行 effect 函数

3. 总结

  • 取值用.valueOf() 。开发者需要时刻注意 proxy 是 String, Number, Boolean 对象,记得调用 .valueOf()方法才能取到实际值。配合 eslint 插件可帮助检查漏写.valueOf()方法
  • 修改用.setValue() 。这种解决方案完整保留 js 语言特性,仅仅只是增加了 .setValue() 方法,对开发者的心智负担可能略少于 ref
  • 实现源码仓库:https://github.com/ruige24601/re-primitive.git

作者:瑞哥24601
链接:https://juejin.im/post/6895213945997492238

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「IT平头哥联盟」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:为什么 Vue3 的 ref 让很多大佬操碎了心?

链接:https://www.javascriptc.com/4757.html

« 这React的7种代码怪味~[译]
VS CODE 轻松调试 Nginx»
Flutter 中文教程资源

相关推荐

QR code