Vue Refの糖衣構文と Svelte
10/28に、Vue の著者ユーさんは Vue Ref の糖衣構文に関する RFC を提案した。
refの定義をJavaScriptラベル構文を使うことでさらに簡略化できます。この構文はSvelteとまったく瓜二つなので、ここで私の考えを書く。
まず、コードを見ていきましょう。
<script setup>
// ラベル構文
ref: count = 1
function inc() {
// .valueせずこのままcountを使える
count++
}
console.log($count.value)
</script>
<template>
<button @click="inc">{{ count }}</button>
</template>
このコードを理解するには、まず Vue Composion APIをどんな役割をしているのかを理解しなければならない。
Vue Composition API はいくつのAPIがあり、変数を reactive にすることができます。例えば:
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
Vue Composition API の ref を使って、変数を reactive になる。つまり変数を更新するたび、画面上使っているDOMは自動的に更新されます。
<template>
<div>{{ count }}</div> // 変数 count が更新されたら DOM も更新されます。
</template>
<script>
export default {
setup() {
return {
count: ref(0)
}
}
}
</script>
React の場合、ちょっと useState
に似たように、setState
を呼び出した場合 DOM が更新されます。Vue の強みは setState
みたいな関数を使わなくてもいいというところだと思います。count.value++
の構文だけで更新されることはとても便利だと思います。
ここで注意しないといけないことがある。ref
を使う場合、本当の値を読み込む場合、.value
しないといけないということです。大したことではないが、少しオーバーヘッドドキュメントも記載されている
- ユーザーは普通の変数か、
ref
の変数か判断する場合がある(まあ、TypeScript使えば大したことではないけど) -
template
で普通にcount
で使えるのに、コードの中でcount.value
使う必要がある。 -
.value
で読み込む必要がある
だから Ref Sugar そういう提案があった:
<script setup>
// ラベルを使って ref を定義する
ref: count = 1
function inc() {
// 直接 count++ できる(まえは count.value++)
count++
}
</script>
<template>
<button @click="inc">{{ count }}</button>
</template>
変換したコードはこうなります
<script setup>
const count = ref(1);
function inc() {
count.value++;
}
console.log(count.value)
</script>
<template>
<button @click="inc">{{ count }}</button>
</template>
この糖衣構文はref
定義を隠していると同時に、.value
を使用せず変数を直接アクセスできるため、開発者に負担が軽減されていることがわかります。
ですが、コミュニティはほぼ反対意見だった。
- これは正しいJavaScript構文ではないこと(ラベル構文自体は合法ですが、同じラベルを定義するのはだめらしい)
- Vueはラベル構文の意味を勝手に変更した
-
let
,const
使わず直接変数を定義することが変。 - コンパイルする必要があって複雑になった。
興味があったらぜひRFCも見てみてください。
著者自身も、このアイデアはSvelteから借用したと述べていますが、Svelteがどのように使っているのかを見てみよう:
<script>
let name = 'world';
// name更新するたびにこのコードを実行される
$: console.log(name);
// name更新するたびにname2に代入
$: name2 = name.toUpperCase();
// マントのときだけ実行
$: console.log('');
</script>
$
ラベルついてるコードは、Svelteによってこんなふうにコンパイルされる
let name2;
$$self.$$.update = () => {
if ($$self.$$.dirty & /*name*/ 1) {
$: console.log(name);
}
if ($$self.$$.dirty & /*name*/ 1) {
$: name2 = name.toUpperCase();
}
};
$: console.log("");
$$self.$$
などまず無視して、update
の関数だけ注視する。update
の関数はコンポネントが更新されたときに実行する。Svelteは変数が更新されているかどうかをまず確認し(if 構文のことろ)、それからコードを実行するかどうかを決定する。
下部のconsole.log()
はコンポーネントの変数を使っていないため、コンパイルされても update
に入れないことがわかります。
3つ以上の変数がある場合、Svelteはどの変数が変更されたかを認識し、対応するコードを実行できます。
let name = 'world';
let count = 0;
// name変更されたら実行する
$: console.log(name);
// count変更されたら実行する
$: console.log(count);
ここで、Svelteが依存関係を可能な限り追跡することがわかります。Reactのふうに変換すると次のようになる
const [name, ] = useState('world');
const [count, ] = useState(0);
useEffect(() => {
console.log(name);
}, [name]);
useEffect(() => {
console.log(count)
}, [count])
つまりSvelteは、コンパイルを通じて内部的にどの依存関係を持っているかを事前に認識し、それを処理できるため、実行時(ランタイム)に依存関係を明示的に宣言する必要はない。
もちろん、この部分にはメリットとデメリットがあり、トレードオフも含まれている。
構文とコンパイルの力を貸して、コードを大幅にシンプル化でき、簡潔なコードで開発者の負担を軽減できることがわかる。
このため、黒魔術と見なされやすいです。
議論をより集中させるためには、魔法の定義が何であるかを明確にする必要があるので、私は魔法を次のように定義する
-
コードの動作が期待と違う
-
コードと実際にコンパイルされたコードと異なる(ラベルのコードはコンパイル後に完全に異なります)
これらの2つの議論に基づいて、さまざまな議論を導き出すことができます。
-
JSX、テンプレート、SFCがJavaScriptコードに処理されますが、それは魔法ですか?開発者が一般的にこの構文を受け入れるのはなぜですか?
-
v-if
v-show
v-for
などフレームワークが提供されたテンプレート構文は魔法にカウントされるのか? -
Reactの
onChange
イベントは、ブラウザのonChange
イベントとは異なりますが、標準を再定義したね。それも魔法ですか?(参考)
ただし、Vue Ref Sugarだけの観点からは、この糖衣構文がもたらすメリットは実際にはかなり限られています。
効果もSvelteとは異なります。Svelteの$
ラベールは、内部依存関係が変更されたときにコードを再実行することですが、Vueのref:
はref変数を定義するだけです。構文は似ていますが、効果は完全に異なる。
まとめ
自分は ref
糖衣構文についても反対意見を持っていますが、ラベル構文を使うわりにそんなにいいところはないと思っています。そもそも ref
や reactive
分けて提供されることについて本当にいいことなのか?
逆に React は比較的に重くてバンドルサイズもちょっと大きいですが、APIは少なくドキュメントもちゃんと書いてくれて、同じ目的を達成するためにReactで書くならちょっと増えるかもしれないが、すべてランタイムだから逆に黒魔術そんなになくていいかもしれません。
まあ結局人々の好みによるかもしれないが、自分を選んだものがちゃんと胸を張って好きって言えばいい。他のフレームワークと強引に比べる筋合いはない。つまらない争いをやめて、お互いの良さを勉強し、一緒によいフレームワークを作ればいいと思う。
Author And Source
この問題について(Vue Refの糖衣構文と Svelte), 我々は、より多くの情報をここで見つけました https://zenn.dev/kalan/articles/6e96e13fb2b0447af4f6著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Collection and Share based on the CC protocol