@spring_raining が @potato4d に、 Vue 3 の Fragment について聞いてみました。
ゲスト
- @potato4d
- フロントエンド開発センター フロントエンドエンジニア
Vue 3 Study
- UIT で行っている Vue 3 についての勉強会
- Vue 3 の RFC を読みながら新しい機能を紹介
Vue 3 Fragment
- Vue 3 で導入される、実際には描画されない DOM 要素のようなもの
- Web 標準に DocumentFragment があり、それを Vue で表現している
- React には
React.Fragment
あるいは<></>
として既に導入されている
Fragment でできること
- これまでは root の
<template></template>
の直下は 1 要素しか受け付けなかった- root でなければ複数要素は許可されていたので、間に何らかのタグを挟むなどがあった
- h1 とメインコンテンツをまとめたコンポーネントなら section を挟むなど
- これからは複数要素を受け付けられるようになり、柔軟性が増す
- 例えば dt / dd をまとめたコンポーネントを作りたい場合などに活用できる
- Vue.js の場合は大きな変化はなさそう
- React の場合は
<template>
に相当するタグがなかったので、見通しを良くするために各所に挟めるのが便利だった - Vue でも
v-if
のためだけの<template>
を用意することがあるように
- React の場合は
- root でなければ複数要素は許可されていたので、間に何らかのタグを挟むなどがあった
- Fragment 利用時の注意点
- コンポーネントの root 要素に、親コンポーネントから付与される属性が自動的に付与されなくなる
- 親から
class="xxx"
といった属性を付与していたケースも多いハズ - Fragment を利用する場合、明示的に
:bind="$attr"
にて属性を付与してやる必要がある
- 親から
- コンポーネントの root 要素に、親コンポーネントから付与される属性が自動的に付与されなくなる
なぜこれまで Fragment ができなかったのか
- Vue 2.x 時代では、コンポーネントのマウントロジックが outerHTML 依存だった
- そのため、描画対象となる DOM そのものを対象として完全なる置き換えをしている
- 単一の要素の DOM を置き換える都合上、1つの枠に2つ以上の DOM を入れることが不可能だった
- Vue 3 では、ロジックの改善によって innerHTML 依存となっている
- これにより、root 要素でも Fragment の実現が容易となった
- コード上も単に children を render しているだけの様子
- https://github.com/vuejs/vue-next/blob/58b07069ad33c8a8e44cb47b81084a452dda2846/packages/runtime-core/src/renderer.ts
- 参考: https://github.com/vuejs/rfcs/blob/master/active-rfcs/0009-global-api-change.md#mounting-behavior-difference-from-2x
- これにより、root 要素でも Fragment の実現が容易となった
現時点での利用上の注意
- Vetur (eslint-plugin-vue) が対応していないため、
vue/valid-template-root
が発生する- 現時点ではまだ変更が取り込まれていない様子。
- Vue 3 に合わせてバージョンアップされる?
- Vue 3 beta にあげていて使いたい場合は、手元の
.eslintrc.js
でvue/valid-template-root
をオフにしてやる必要がある
- 現時点ではまだ変更が取り込まれていない様子。