关于前端:译尤雨溪-Ref语法糖提案

40次阅读

共计 5633 个字符,预计需要花费 15 分钟才能阅读完成。

前言

最近 ref 的语法糖引起了极大的争议,很多人也是没看 RFC 就间接开喷,尽管我也不喜爱这种语法,但还是有必要让大家看一看在 GitHub 上的提案,看看国外开发者们广泛都是些什么态度,是否和咱们持有同样的观点,提案是 RFC 228,但 RFC 228 其实是为了不便与另一个提案辨别开而新开的,原提案是 RFC 222,它最终被分解成了 RFC 227 和 RFC 228,所以咱们先从 RFC 222 开始翻译。

译文

尤雨溪

简介

  • 在单文件组件 (xxx.vue) 中引入了一个新的 script 类型:<script setup>,这种写法会主动将所有顶级变量申明裸露给 <template> 应用。
  • 介绍一个基于编译器的语法糖,这种语法糖能够在 <script setup> 中让你的 ref 不必再写 .value 属性了。
  • 留神,本提案意在代替 RFC 182 提出的 <script setup> 写法。

根本用法

  1. <script setup> 间接向 <template> 裸露顶级变量

⚠️译者注: 顶级变量就是没申明在块级作用域外面的变量

<script setup>
// 引入的 Foo 组件能够间接在 template 里应用了!import Foo from './Foo.vue'
  
import {ref} from 'vue'

// 就像在一般的 setup() 中一样编写 Composition API 代码,// 无需手动返回所有内容
const count = ref(0)
const inc = () => { count.value++}
</script>

<template>
  <Foo :count="count" @click="inc" />
</template>

???? 下面的这段代码将会编译成上面这样????:

<script setup>
import Foo from './Foo.vue'
import {ref} from 'vue'

export default {setup() {const count = ref(1)
    const inc = () => { count.value++}

    return {
      Foo, // 即便 Foo 组件不是被申明的,也会把它算作顶级变量
      count,
      inc
    }
  }
}
</script>

<template>
  <Foo :count="count" @click="inc" />
</template>
  1. ref:语法糖令代码更简洁
<script setup>
// 申明一个变量(这个变量将会被编译成一个 ref)
ref: count = 1

function inc() {
  // 该变量能够像一般变量那样应用
  count++
}

// 想要获取到本来的变量的话须要在变量后面加一个???? 符号
console.log($count.value)
</script>

<template>
  <button @click="inc">{{count}}</button>
</template>

???? 下面的这段代码将会编译成上面这样????:

<script setup>
import {ref} from 'vue'

export default {setup() {const count = ref(1)

    function inc() {count.value++}

    console.log(count.value)

    return {
      count,
      inc
    }
  }
}
</script>

<template>
  <button @click="inc">{{count}}</button>
</template>

评论之前:

  • 请确保曾经读完残缺的 RFC
  • 请不要简略地答复 ” 我喜爱 / 我不喜爱 ”- 它不会对探讨做出有意义的奉献。
  • 如果不赞成该提案,请在动机和弊病中提出的观点范畴内进行具体论证。请留神,这中语法是 JavaScript 中的标签语法。咱们只是给 ref: 这个标签提供了不同的语义。这就像在 HTML 写 Vue 指令一样。

⚠️译者注:而后接下来是高赞回复:

耶姆贾森(ycmjason ????????)

只是一个意见:

真的不喜爱这个主见。发明的语法太多了。而且这曾经不再是 JavaScript 了。

尤雨溪(回复)

你这种反馈在咱们的意料之中,我晓得这可能会引起争议,因而对于其余任何评论:

  • 请确保曾经读完残缺的 RFC
  • 请不要简略地答复 ” 我喜爱 / 我不喜爱 ”- 它不会对探讨做出有意义的奉献。
  • 如果不赞成该提案,请在动机和弊病中提出的观点范畴内进行具体论证。

私人号码(privatenumber ???????? ????????)

编译器会主动将所有导入的 xxx.vue 文件注册为组件吗?

具体来说,我很好奇编译器怎么辨认什么是 Vue 组件,什么不是。如果我导入一个 xxx.js 模式的组件,那还能够应用吗?

如果咱们用到了高阶组件的话,也可能不心愿这个导入的高阶组件被主动注册成组件。

如果咱们要增加自定义语法,那么 ES2021 的 export default from 语法是否能够施行?

我感觉这种写法可能既简洁又明确:

export {default as Foo} from './Foo.vue';

尤雨溪(回复)

编译器能够通过 setup 上下文来判断。模板编译器会从 script 编译时提取绑定信息判断该组件是否可用。

我认为导入 xxx.vue 并利用高阶组件的模式去包装是十分常见的一种状况。在这种状况下,您能够应用独自的惯例 <script> 标签用以前的形式去注册组件。

必图(btoo ????????)

我宁愿用 svelte 的 $: 而不是 svelte-ref: 这种模式。

其实也能够通过在变量名前增加一个 $ 前缀来放弃拜访原始 ref 的形式。

⚠️译者注:svelte 是国外另一款特地火的框架,这个提案的灵感就来源于这个 svelte 的写法

约翰逊(johnsoncodehk ????????)

⚠️译者注:这个人不是高赞 (????),而是高踩(????),咱们看看也别光看高赞,高踩也挺有意思
$: + let / const 这种写法怎么样怎么样?
就像这样:

$: let foo = 1 // 这个变量代表 ref
$: const bar = foo + 1 // 这个变量代表 computed
$: let baz = computed(() => bar + 1)

而后会被编译成这样:

const $foo = ref(1)
let foo = unref($foo)
const $bar = computed(() => foo + 1)
const bar = unref($bar)
const $baz = ref(computed(() => bar + 1))
let baz = unref($baz)

我感觉大家如同都不想脱离 js 的语义,当然咱们能够有一种齐全基于 js 语义的办法,但这是咱们想要的吗:

import {noValueRef, noValueComputed} from 'vue'
let foo = noValueRef(1) // TS 类型: number & {raw: Ref<number>}
const bar = noValueComputed(() => foo + 1) // TS 类型: number & {raw: ComputedRef<number>}
useNum(bar.raw)
function useNum(num: Ref<number>)

而后会被编译成这样:

import {ref, computed} from 'vue'
let foo = ref(1)
const bar = computed(() => foo.value + 1)
useNum(bar)
function useNum(num: Ref<number>)

喜爱的点赞(????),不喜爱就踩(????)

⚠️译者注:下面那句话是他说的不是我说的,果然亚洲都喜爱玩这一套

罗宾鲍乌(RobbinBaauw ????????)

这个 RFC 的毛病 (<script setup> 自身也是一个毛病,但当初变得更糟) 是编写大量雷同内容的 options。经验丰富的 Vue 开发者 (例如对此 RFC 进行评论的这帮人) 理解所有的 options,理解它们之间的关系等,然而对于 Vue 的大部分开发者而言,状况并非如此。

在 Vue2 中,只有 Options API,最终咱们会失去一个相似类一样的组件。然而如果用了这个 RFC,咱们将会面临以下抉择:

  • Options API
  • Class API (须要用插件)
  • Composition API (vue2 和 vue3 的写法也不一样)
  • \<script setup> 搭配 ref: 语法糖
  • \<script setup> 不搭配语法糖

这会让用户群变得十分扩散,让刚入门的小白和有抉择艰难症的人感觉太难了。如果只须要记住:” 想要响应式就用 Options API,不便逻辑复用就用 Composition API” 的话那就会简略多了。

然而很显著,不少人喜爱这种 ” 神奇的 ” 语法。如果有人再提出个什么自定义的语法说不定当前还会想再扩大语法,能不能在 Vue 以外的第三方库去实现它?如果这是 Vue 的外围语法,那么在当前的 Vue 版本中都将须要反对它。

我认为这个 $ 十分令人纳闷:如果您不齐全理解 $ 前缀的前因后果,我认为这将会令人十分纳闷!也就是说,须要晓得一个这玩意是个 ref 的理论值,并且还须要晓得本人正在解决的是一个加了语法糖的 ref,在这种状况下须要给它加上 $ 前缀,而在其余状况下,则不须要加前缀。我深信这会给许多用户带来很多问题。

尤雨溪(回复)

你说的太夸大了。

Class API 是一个官网插件,但只是一个插件。不是外围 API 的一部分,仅吸引特地偏爱 Class 的用户。换句话说,它不是 ” 支流 ”。

⚠️译者注:不是支流那不就是 非主流

vue2 和 vue3 的 Composition API 的目标是雷同的,并且即便不是全副,也至多是大多数代码看起来雷同。渺小的技术差别不会将它们视为 ” 做同一件事的两种形式 ”。

<script setup> 就如 RFC 中所倡议的那样,用不含语法糖编写的 Composition API 代码与失常的 Composition API 应用状况 100% 雷同 ( 除了无需手动返回所有内容)。实际上,如果用户应用的是但文件组件的话,因为前者总是只用写更少的代码,所以我真找不到不必新 <script setup> 的理由。

难道你感觉这么写更好吗:

export default {components: {...},
  setup() { ...}
}

ref:是纯语法糖。它不会扭转 <script setup> 外面 Composition API 的工作形式。如果你曾经了解了 Composition API,那么了解 ref: 语法糖不会超过 10 分钟。

综上所述 - 有两个 ” 范例 ”:
(1)Options API
(2)Composition API
<script setup> 和 ref: 语法糖不是不同的 API 或范例。它们只是 Composition API 的扩大,能够用更少的代码来表白雷同的逻辑。

(援用罗宾方才说的话):如果有人再提出个什么自定义的语法说不定当前还会想再扩大语法,能不能在 Vue 以外的第三方库去实现它?

所以,你也批准很多人都心愿应用 ref: 语法糖,然而却倡议不要在 Vue 中反对它,而是激励各种第三方库各自实现本人的语法。这不是只会导致更多的碎片化吗?想想 React 生态系统中的 CSS-in-JS。

(援用罗宾方才说的话):我认为这个 $ 十分令人纳闷:如果您不齐全理解 $ 前缀的前因后果,我认为这将会令人十分纳闷!也就是说,须要晓得一个这玩意是个 ref 的理论值,并且还须要晓得本人正在解决的是一个加了语法糖的 ref,在这种状况下须要给它加上 $ 前缀,而在其余状况下,则不须要加前缀。我深信这会给许多用户带来很多问题。。

$foo 其实就代表 foo 就好比 foo 就代表 foo.value。真的那么令人蛊惑吗?这会导致什么确切的具体问题?遗记 $ 何时增加?请留神,即便没有语法糖,咱们也遗记什么时候该用.value,后者更可能产生。

你是在要求用户放弃 Composition API 的益处,因为您不喜爱语法糖,因为语法糖会使 Composition API 变得不太简短。我真的认为没有情理。

林纳斯·伯格(LinusBorg ????????)

如果 <script setup> 当初间接向 <template> 模板公开顶级变量

那将如何解决两头变量:

const store = inject('my-store')

ref: stateICareAbout = computed(() => store.state.myState)

function addState(newState) {store.add(newState)
}

即便 store 这个变量不须要公开到 <template> 下来,也会裸露给 <template> 模板。但这实际上是一个问题吗?

不利的一面是: 它将使生成的代码变大,因为它会使设置返回的对象变大,并且咱们对模板所裸露的内容失去了一些 ” 清晰度 ”。

从好的方面来说,人们可能会辩论说,明确定义裸露于模板的内容太麻烦啦,感觉 <template> 当初更像是 JSX 了。

尤雨溪(回复)

是的,所有顶级变量都会裸露在外。从技术上讲,如果将其合并,咱们还能够引入另一种模板编译模式,在该模式下,间接从 setup 中 return 一个 render 函数。这使得作用域更加间接,并且防止了 render proxy。

埃勒夫(iNerV ????????)

这太蹩脚了。我不想在 Vue 中看到 svelte。(不想看到不非法的 js 语法)

总结

总体来说,持拥护态度的人占多数,和国内差不多,不过看到这么多不同国籍的人在这里探讨还挺有意思的,然而中国???????? 的声音却非常少,好不容易看到一个还是香港???????? 的,大家也能够去 GitHub 上间接舌战群儒。

当然哈,别用中文,毕竟你要让所有国籍的人都能看懂 ( 至多是勉强看懂,我翻译荷兰那小子的英文,感觉说的也不咋地,咱们英文不比他们差),设想一下这些人如果都用本人的母语发表观点的话咱们还怎么读懂。强行用中文的话同胞们看着是难受了,然而会导致咱们在国内上的名声进一步下滑。

大家在去 GitHub 探讨的时候还是要尽量维持一下咱们国家在国内上的形象哈!

该文章首发于公众号:《前端学不动》

正文完
 0