vue の ref と 参照渡しの違い
vue の ref
内部値を受け取り、リアクティブでミュータブルな ref オブジェクトを返します。またそれは、内部値を示した単一プロパティである .value を持っています。
参照渡し
参照呼び(call by reference、参照渡し: pass by reference)では、仮引数が実引数そのもの、すなわちエイリアス(Aliasing)になる。実引数は、左辺値を持たねばならない(Pascalのように、実引数を変数に限定した言語もある)か、左辺値を持たない式の場合は呼び出し側で一時的オブジェクトを構築する言語もある。
ref | 参照渡し | |
---|---|---|
値の保存先 | ref 自身 | 参照されている変数 |
値の代入 | .value が必要(= エイリアスにならない) | 代入すれば参照されている変数に反映される |
Reactivity Transform
Composition API が導入されてから、ref と reactive オブジェクトの使い分けは主要な未解決問題のひとつです。リアクティブなオブジェクトを分割代入するとリアクティビティーが失われやすく、一方、ref を使用する場合は .value をあらゆる場所で使用するのは面倒なことです。また、型システムを使用していない場合、.value を見落としがちです。
Vue Reactivity Transform はコンパイル時に変換して、以下のようなコードを書けるようにします:
<script setup> let count = $ref(0) console.log(count) function increment() { count++ } </script> <template> <button @click="increment">{{ count }}</button> </template>
ここでの $ref() メソッドは コンパイルタイムマクロ です。実行時に呼び出される実際のメソッドではなく、Vue のコンパイラーは、結果の count 変数を リアクティブな変数 として扱うためのヒントとして使用します。
リアクティブな変数は通常の変数と同じようにアクセスしたり再代入できますが、これらの操作は .value つきの ref にコンパイルされます。例えば、上記コンポーネントの <script> 部分は以下のようにコンパイルされます:
import { ref } from 'vue' let count = ref(0) console.log(count.value) function increment() { count.value++ }
Reactivity Transform 廃止理由
The original goal of Reactivity Transform was to improve the developer experience by providing more succinct syntax when working with reactive state. We shipped it as experimental to gather feedback from real world usage. Despite the proposed benefits, we discovered the following issues:
- Losing .value makes it harder to tell what is being tracked and which line is triggering a reactive effect. This problem is not so noticeable inside small SFCs, but the mental overhead becomes much more noticeable in large codebases, especially if the syntax is also used outside of SFCs.
- Because of (1), some users opted to only use Reactivity Transform inside SFCs, which creates inconsistency and cost of context-shifting between different mental models. So, the dilemma is that using it only inside SFCs leads to inconsistency, but using it outside SFCs hurts maintainability.
- Since there will still be external functions that expect to work with raw refs, the conversion between Reactive Variables and raw refs is inevitable. This ends up adding one more thing to learn and extra mental burden, and we noticed this confuses beginners more than plain Composition API.
And most importantly, the potential risk of fragmentation. Despite this being clearly opt-in, some users have expressed strong objections against the proposal, the reason being that they fear that they would have to work with different codebases where some opted to use it while some not. This is a valid concern because Reactivity Transform entails a different mental model that distorts JavaScript semantics (variable assignments being able to trigger reactive effects).
All things considered, we believe landing it as a stable feature would result in more issues than benefits, and thus not a good trade-off.
にゅあんす的には
-
.value
がなくなると ref であることがわからなくなる - 上記の問題により SFC でのみ利用することにしたが、SFC外での不整合により 保守性が下がるジレンマが発生する
- 本来の ref と Reactive Variables 間での変換が必要であり、考えることが増えて煩雑化する(=単純な Composition API よりも初心者を混乱させる)
最もな問題は 適用していない環境との断片化のリスク(マクロによってアクセスが .value
を隠蔽する為このマクロを適用していない環境と大きく異なってしまう為
以上のことを踏まえると メリットよりも問題の方が勝る
とのこと。