シンプルさ、モジュール性、強力な機能、パフォーマンスに焦点を当てた仮想DOMライブラリ。
優れたクロスブラウザーテストツールへのアクセスを提供してくれたBrowserstackに感謝します。
英語| 简体中文|ヒンディー語
仮想Domは素晴らしいです。これにより、アプリケーションの見解を状態の関数として表現できます。しかし、既存のソリューションはあまりにも肥大化しており、遅すぎる、機能が不足している、APIがOOPに向かって偏っている、および/または私が必要としていた機能が不足していた。
Snabbdomは、非常にシンプルで、パフォーマンスがあり、拡張可能なコアで構成されており、わずか200 SLOCです。カスタムモジュールを介して拡張機能を備えた豊富な機能を備えたモジュラーアーキテクチャを提供します。コアをシンプルに保つために、すべての非必須機能はモジュールに委任されます。
あなたはあなたが望むものに味わいを形作ることができます!必要な機能を選択、選択、カスタマイズします。または、デフォルトの拡張機能を使用して、高性能、小型サイズ、および以下にリストされているすべての機能を備えた仮想DOMライブラリを取得できます。
h機能仮想DOMノードを簡単に作成します。hヘルパーで動作します。 import {
init ,
classModule ,
propsModule ,
styleModule ,
eventListenersModule ,
h
} from "snabbdom" ;
const patch = init ( [
// Init patch function with chosen modules
classModule , // makes it easy to toggle classes
propsModule , // for setting properties on DOM elements
styleModule , // handles styling on elements with support for animations
eventListenersModule // attaches event listeners
] ) ;
const container = document . getElementById ( "container" ) ;
const vnode = h (
"div#container.two.classes" ,
{ on : { click : ( ) => console . log ( "div clicked" ) } } ,
[
h ( "span" , { style : { fontWeight : "bold" } } , "This is bold" ) ,
" and this is just normal text" ,
h ( "a" , { props : { href : "/foo" } } , "I'll take you places!" )
]
) ;
// Patch into empty DOM element – this modifies the DOM as a side effect
patch ( container , vnode ) ;
const newVnode = h (
"div#container.two.classes" ,
{ on : { click : ( ) => console . log ( "updated div clicked" ) } } ,
[
h (
"span" ,
{ style : { fontWeight : "normal" , fontStyle : "italic" } } ,
"This is now italic type"
) ,
" and this is still just normal text" ,
h ( "a" , { props : { href : "/bar" } } , "I'll take you places!" )
]
) ;
// Second `patch` invocation
patch ( vnode , newVnode ) ; // Snabbdom efficiently updates the old view to the new state initpatchhfragment (実験的)toVNodeinitフックinsertフックremoveフックdestroyフックremoveでプロパティを設定しますdestroyにプロパティを設定しますSnabbdomのコアは、最も重要な機能のみを提供します。速くて拡張可能でありながら、できるだけシンプルであるように設計されています。
initコアは、単一の関数initのみを公開します。このinit 、モジュールのリストを取得し、指定されたモジュールセットを使用するpatch関数を返します。
import { classModule , styleModule } from "snabbdom" ;
const patch = init ( [ classModule , styleModule ] ) ;patch initによって返されるpatch関数は、2つの引数を取ります。 1つ目は、現在のビューを表すDOM要素またはVNodeです。 2番目は、新しい更新されたビューを表すVNodeです。
親を持つDOM要素が渡されると、 newVnode DOMノードに変わり、渡された要素は作成されたDOMノードに置き換えられます。古いvNodeが渡されると、Snabbomはそれを効率的に変更して、新しいVNodeの説明に一致します。
渡された古いVNodeは、以前のpatchへの呼び出しから得られたVNodeでなければなりません。これは、snabbdomがVNodeに情報を保存するため、必要です。これにより、よりシンプルでパフォーマンスの高いアーキテクチャを実装できます。これにより、新しい古いVNodeツリーの作成も回避されます。
patch ( oldVnode , newVnode ) ; マウントポイント要素からVNodeツリーを削除するためのAPIはありませんが、これをほとんど達成する1つの方法は、次のようなpatchへの2番目の引数としてコメントvNodeを提供することです。
patch (
oldVnode ,
h ( "!" , {
hooks : {
post : ( ) => {
/* patch complete */
}
}
} )
) ;もちろん、マウントポイントにまだ1つのコメントノードがあります。
h hを使用してvNodesを作成することをお勧めします。タグ/セレクターを文字列、オプションのデータオブジェクト、オプションの文字列または子供の配列として受け入れます。
import { h } from "snabbdom" ;
const vnode = h ( "div#container" , { style : { color : "#000" } } , [
h ( "h1.primary-title" , "Headline" ) ,
h ( "p" , "A paragraph" )
] ) ;fragment (実験的)注意:この機能は現在実験的であり、オプトインする必要があります。そのAPIは、メジャーバージョンバンプなしで変更される場合があります。
const patch = init ( modules , undefined , {
experimental : {
fragments : true
}
} ) ;与えられた子供を含むドキュメントフラグメントに変換される仮想ノードを作成します。
import { fragment , h } from "snabbdom" ;
const vnode = fragment ( [ "I am" , h ( "span" , [ " a" , " fragment" ] ) ] ) ;toVNodeDOMノードを仮想ノードに変換します。特に既存のサーバー側で生成されたHTMLコンテンツにパッチを当てるのに適しています。
import {
init ,
styleModule ,
attributesModule ,
h ,
toVNode
} from "snabbdom" ;
const patch = init ( [
// Initialize a `patch` function with the modules used by `toVNode`
attributesModule // handles attributes from the DOM node
datasetModule , // handles `data-*` attributes from the DOM node
] ) ;
const newVNode = h ( "div" , { style : { color : "#000" } } , [
h ( "h1" , "Headline" ) ,
h ( "p" , "A paragraph" ) ,
h ( "img" , { attrs : { src : "sunrise.png" , alt : "morning sunrise" } } )
] ) ;
patch ( toVNode ( document . querySelector ( ".container" ) ) , newVNode ) ;フックは、DOMノードのライフサイクルに接続する方法です。 Snabbdomはフックの豊富なセレクションを提供します。フックは、モジュールの両方で使用され、Snabddomを拡張し、仮想ノードの寿命において目的のポイントで任意のコードを実行するための通常のコードで使用されます。
| 名前 | いつトリガーされます | コールバックへの引数 |
|---|---|---|
pre | パッチプロセスが開始されます | なし |
init | VNodeが追加されました | vnode |
create | VNodeに基づいてDOM要素が作成されました | emptyVnode, vnode |
insert | 要素がDOMに挿入されています | vnode |
prepatch | 要素にパッチを適用しようとしています | oldVnode, vnode |
update | 要素が更新されています | oldVnode, vnode |
postpatch | 要素がパッチされています | oldVnode, vnode |
destroy | 要素は、直接的または間接的に削除されています | vnode |
remove | 要素はDOMから直接削除されています | vnode, removeCallback |
post | パッチプロセスが完了しました | なし |
次のフックは、モジュールで利用できます: pre 、 create 、 update 、 destroy 、 remove 、 post 。
次のフックは、個々の要素のhookプロパティで利用できます: init 、 create 、 insert 、 prepatch 、 update 、 postpatch 、 destroy 、 remove 。
フックを使用するには、データオブジェクト引数のフィールドをhookオブジェクトとしてそれらを渡します。
h ( "div.row" , {
key : movie . rank ,
hook : {
insert : ( vnode ) => {
movie . elmHeight = vnode . elm . offsetHeight ;
}
}
} ) ; initフックこのフックは、新しい仮想ノードが見つかったパッチプロセス中に呼び出されます。 Snabbomがノードを何らかの方法で処理する前にフックが呼び出されます。つまり、VNodeに基づいてDOMノードを作成する前に。
insertフックこのフックは、VNodeのDOM要素がドキュメントに挿入され、パッチサイクルの残りの部分が完了すると呼び出されます。これは、DOM測定を実行できることを意味します(このフックでGetBoundingClientRectを安全に使用するなど、挿入された要素の位置に影響を与える可能性のある要素が変更されないことを知っています。
removeフック要素の削除に接続できます。フックは、vNodeがDOMから削除されると呼ばれます。処理関数は、VNodeとコールバックの両方を受信します。コールバックで削除を制御および遅延させることができます。フックがそのビジネスを行うと、コールバックを呼び出す必要があり、すべてのremoveフックがコールバックを呼び出した場合にのみ、要素が削除されます。
フックは、要素を親から削除する場合にのみトリガーされます。削除された要素の子である場合ではありません。そのためには、 destroyフックを参照してください。
destroyフックこのフックは、DOM要素がDOMから削除された場合、または親がDOMから削除されている場合、仮想ノードに呼び出されます。
このフックとremoveフックの違いを確認するには、例を考えてください。
const vnode1 = h ( "div" , [ h ( "div" , [ h ( "span" , "Hello" ) ] ) ] ) ;
const vnode2 = h ( "div" , [ ] ) ;
patch ( container , vnode1 ) ;
patch ( vnode1 , vnode2 ) ;ここでは、内側のdiv要素とそれに含まれるspan要素の両方にdestroyされます。一方、 remove 、親から切り離されている唯一の要素であるため、 div要素にのみトリガーされます。
たとえば、 removeを使用して、要素が削除されているときにアニメーションをトリガーし、 destroyフックを使用して、削除された要素の子供の消失をさらにアニメーション化できます。
モジュールは、フックのグローバルリスナーを登録することで動作します。モジュールは、機能へのフック名をマッピングする辞書です。
const myModule = {
create : ( oldVnode , vnode ) => {
// invoked whenever a new virtual node is created
} ,
update : ( oldVnode , vnode ) => {
// invoked whenever a virtual node is updated
}
} ;このメカニズムを使用すると、Snabbdomの挙動を簡単に増強できます。デモンストレーションについては、デフォルトモジュールの実装を見てください。
これは、コアモジュールについて説明します。すべてのモジュールはオプションです。 JSXの例は、このライブラリが提供するjsxプラグマを使用していると仮定しています。
クラスモジュールは、要素のクラスを動的に切り替える簡単な方法を提供します。 classデータプロパティにオブジェクトが期待されます。オブジェクトは、クラスがvnodeにとどまるかどうかを示すクラス名をブール付けにマッピングする必要があります。
h ( "a" , { class : { active : true , selected : false } } , "Toggle" ) ; JSXでは、次のようなclassを使用できます。
< div class = { { foo : true , bar : true } } />
// Renders as: <div class="foo bar"></div>DOM要素にプロパティを設定できます。
h ( "a" , { props : { href : "/foo" } } , "Go to Foo" ) ; JSXでは、次のようなpropsを使用できます。
< input props = { { name : "foo" } } />
// Renders as: <input name="foo" /> with input.name === "foo"プロパティのみを設定できます。削除されません。ブラウザはカスタムプロパティの追加と削除を可能にしますが、このモジュールによって削除は試みられません。ネイティブDOMプロパティを削除できないため、これは理にかなっています。また、値を保存したり、DOMにオブジェクトを参照するためにカスタムプロパティを使用している場合は、代わりにデータ - *属性の使用を検討してください。おそらくデータセットモジュールを介して。
小道具と同じですが、DOM要素のプロパティの代わりに属性を設定します。
h ( "a" , { attrs : { href : "/foo" } } , "Go to Foo" ) ; JSXでは、次のようなattrs使用できます。
< div attrs = { { "aria-label" : "I'm a div" } } />
// Renders as: <div aria-label="I'm a div"></div>属性は、 setAttributeを使用して追加および更新されます。以前に追加/セットされていて、 attrsオブジェクトに存在しなくなった属性の場合、 removeAttributeを使用してDOM Elementの属性リストから削除されます。
Boolean属性( disabled 、 hidden 、 selected ...)の場合、意味は属性値( trueまたはfalse )に依存するのではなく、代わりにDOM要素に属性自体の存在/欠如に依存します。これらの属性は、モジュールによって異なる方法で処理されます。ブール属性がfalsy値( 0 、 -0 、 null 、 false 、 NaN 、 undefined 、または空の文字列( "" )に設定されている場合、属性はdom要素の属性リストから削除されます。
DOM要素にカスタムデータ属性( data-* )を設定できます。これらは、htmlelement.datasetプロパティでアクセスできます。
h ( "button" , { dataset : { action : "reset" } } , "Reset" ) ; JSXでは、次のようなdatasetを使用できます。
< div dataset = { { foo : "bar" } } />
// Renders as: <div data-foo="bar"></div>スタイルモジュールは、HTMLを滑らかに見せてアニメーション化するためのものです。そのコアでは、要素にCSSプロパティを設定できます。
h (
"span" ,
{
style : {
border : "1px solid #bada55" ,
color : "#c0ffee" ,
fontWeight : "bold"
}
} ,
"Say my name, and every colour illuminates"
) ; JSXでは、このようなstyleを使用できます。
< div
style = { {
border : "1px solid #bada55" ,
color : "#c0ffee" ,
fontWeight : "bold"
} }
/>
// Renders as: <div style="border: 1px solid #bada55; color: #c0ffee; font-weight: bold"></div> CSSカスタムプロパティ(別名CSS変数)はサポートされています--
h (
"div" ,
{
style : { "--warnColor" : "yellow" }
} ,
"Warning"
) ; プロパティを遅延として指定できます。これらのプロパティが変更されるたびに、次のフレームの後まで変更は適用されません。
h (
"span" ,
{
style : {
opacity : "0" ,
transition : "opacity 1s" ,
delayed : { opacity : "1" }
}
} ,
"Imma fade right in!"
) ;これにより、要素のエントリを宣言して簡単にアニメーション化できます。
transition-propertyのall価値はサポートされていません。
removeでプロパティを設定しますremoveプロパティに設定されたスタイルは、要素をDOMから削除しようとすると有効になります。適用されたスタイルは、CSS遷移でアニメーション化する必要があります。すべてのスタイルがアニメーション化されたら、要素がDOMから削除されます。
h (
"span" ,
{
style : {
opacity : "1" ,
transition : "opacity 1s" ,
remove : { opacity : "0" }
}
} ,
"It's better to fade out than to burn away"
) ;これにより、要素の削除を宣言的にアニメーション化することができます。
transition-propertyのall価値はサポートされていません。
destroyにプロパティを設定します h (
"span" ,
{
style : {
opacity : "1" ,
transition : "opacity 1s" ,
destroy : { opacity : "0" }
}
} ,
"It's better to fade out than to burn away"
) ; transition-propertyのall価値はサポートされていません。
イベントリスナーモジュールは、イベントリスナーを添付するための強力な機能を提供します。
聴きたいイベントの名前に対応するプロパティをonで提供することにより、VNODE上のイベントに関数を添付できます。イベントが発生したときに関数が呼び出され、それに属するイベントオブジェクトに渡されます。
function clickHandler ( ev ) {
console . log ( "got clicked" ) ;
}
h ( "div" , { on : { click : clickHandler } } ) ; JSXでは、次のようon使用できます。
< div on = { { click : clickHandler } } />Snabbdomを使用すると、レンダリング間でイベントハンドラーを交換できます。これは、DOMに接続されたイベントハンドラーに実際に触れることなく発生します。
ただし、このモジュールがイベントハンドラーをDOMに再結合しないように使用する手法のため、イベントハンドラーをVNodes間で共有するときは注意する必要があることに注意してください。 (一般的に、モジュールが指定されたデータを変異させることが許可されているため、VNodes間でデータを共有することは保証されません)。
特に、このようなことをしてはいけません。
// Does not work
const sharedHandler = {
change : ( e ) => {
console . log ( "you chose: " + e . target . value ) ;
}
} ;
h ( "div" , [
h ( "input" , {
props : { type : "radio" , name : "test" , value : "0" } ,
on : sharedHandler
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "1" } ,
on : sharedHandler
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "2" } ,
on : sharedHandler
} )
] ) ;そのような多くの場合、代わりにアレイベースのハンドラーを使用できます(上記)。または、各ノードが値on一意に渡されていることを確認してください。
// Works
const sharedHandler = ( e ) => {
console . log ( "you chose: " + e . target . value ) ;
} ;
h ( "div" , [
h ( "input" , {
props : { type : "radio" , name : "test" , value : "0" } ,
on : { change : sharedHandler }
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "1" } ,
on : { change : sharedHandler }
} ) ,
h ( "input" , {
props : { type : "radio" , name : "test" , value : "2" } ,
on : { change : sharedHandler }
} )
] ) ; SVGは、仮想ノードを作成するためにh関数を使用するときに機能します。 SVG要素は、適切な名前空間で自動的に作成されます。
const vnode = h ( "div" , [
h ( "svg" , { attrs : { width : 100 , height : 100 } } , [
h ( "circle" , {
attrs : {
cx : 50 ,
cy : 50 ,
r : 40 ,
stroke : "green" ,
"stroke-width" : 4 ,
fill : "yellow"
}
} )
] )
] ) ;SVGの例とSVG Carouselの例も参照してください。
特定のブラウザ(IE <= 11など)は、SVG要素のclassListプロパティをサポートしません。クラスモジュールはclassList内部的に使用するため、クラスリストポリフィルを使用しない限り、この場合は機能しません。 (ポリフィルを使用したくない場合は、属性モジュールでclass属性を使用できます)。
thunk関数は、サンクを識別するためのキーであるセレクター、VNodeを返す関数、およびさまざまな量の状態パラメーターを取ります。呼び出された場合、レンダリング関数は状態引数を受け取ります。
thunk(selector, key, renderFn, [stateArguments])
renderFn 、 renderFnが変更された場合、または[stateArguments]配列の長さまたはその要素が変更された場合にのみ呼び出されます。
keyオプションです。 selectorサンクスの兄弟の間でユニークではない場合に提供する必要があります。これにより、拡散時にサンクが常に正しく一致することが保証されます。
サンクスは、不変のデータを扱っているときに使用できる最適化戦略です。
数字に基づいて仮想ノードを作成するための単純な関数を検討してください。
function numberView ( n ) {
return h ( "div" , "Number is: " + n ) ;
}ビューはnにのみ依存します。これは、 nが変更されていない場合、仮想DOMノードを作成して古いvNodeに対してパッチを当てることを意味します。オーバーヘッドを回避するためにthunkヘルパー機能を使用できます。
function render ( state ) {
return thunk ( "num" , numberView , [ state . number ] ) ;
}実際にnumberView関数を呼び出す代わりに、これは仮想ツリーにダミーVNodeのみを配置します。 SnabbdomがこのダミーVNodeを以前のVNodeに対してパッチすると、 nの値を比較します。 nが変更されていない場合、古いvNodeを再利用するだけです。これにより、数値ビューとdiffプロセスが完全に再作成されます。
ここでのビュー関数は、例のみです。実際には、生成するのに重要な計算時間がかかる複雑なビューをレンダリングする場合にのみ、サンクが関連しています。
JSXフラグメントはまだ実験的であり、オプトインする必要があることに注意してください。詳細については、 fragmentセクションを参照してください。
次のオプションをtsconfig.jsonに追加します。
{
"compilerOptions" : {
"jsx" : " react " ,
"jsxFactory" : " jsx " ,
"jsxFragmentFactory" : " Fragment "
}
}次に、 .tsxファイル拡張子を使用し、ファイルの上部にjsx関数とFragment関数をインポートするようにしてください。
import { Fragment , jsx , VNode } from "snabbdom" ;
const node : VNode = (
< div >
< span > I was created with JSX </ span >
</ div >
) ;
const fragment : VNode = (
< >
< span > JSX fragments </ span >
are experimentally supported
</ >
) ;Babel構成に次のオプションを追加します。
{
"plugins" : [
[
" @babel/plugin-transform-react-jsx " ,
{
"pragma" : " jsx " ,
"pragmaFrag" : " Fragment "
}
]
]
}次に、ファイルの上部にjsx関数とFragment関数をインポートします。
import { Fragment , jsx } from "snabbdom" ;
const node = (
< div >
< span > I was created with JSX </ span >
</ div >
) ;
const fragment = (
< >
< span > JSX fragments </ span >
are experimentally supported
</ >
) ; プロパティ
selプロパティは、vNodeのHTML要素を指定します。オプションでは、 #が付けられたid 、およびそれぞれaでプレミキスされたゼロ以上のクラスを指定します. 。構文は、CSSセレクターに触発されています。ここにいくつかの例があります:
div#container.bar.baz - ID containerとクラスbarとbaz備えたdiv要素。li - idもクラスもないli要素。button.alert.primary - 2つのクラスがalertとprimary備えたbutton要素。セレクターは静的であることを意図しています。つまり、要素の寿命にわたって変化してはなりません。動的idを設定するには、Propsモジュールを使用し、動的クラスを設定するには、クラスモジュールを使用します。
セレクターは静的であるため、SnabdomはVNodes IDの一部として使用します。たとえば、2人の子供がvnodeしている場合
[ h ( "div#container.padding" , children1 ) , h ( "div.padding" , children2 ) ] ;反対しています
[ h ( "div#container.padding" , children2 ) , h ( "div.padding" , children1 ) ] ;次に、Snabbomはセレクターを使用してVNodeを識別し、新しいDOM要素を作成する代わりにDOMツリーに並べ替えます。このセレクターの使用は、多くの場合、キーを指定する必要性を回避します。
仮想ノードの.dataプロパティは、作成時に実際のDOM要素にアクセスして操作するための情報を追加する場所です。スタイル、CSSクラス、属性などを追加します。
データオブジェクトは(オプションの) h()への2番目のパラメーターです
たとえば、 h('div', {props: {className: 'container'}}, [...])仮想ノードを生成します
( {
props : {
className : "container"
}
} ) ; .dataオブジェクトとして。
Virtual Nodeの.childrenプロパティは、作成中の3番目の(オプション) h()へのパラメーターです。 .children 、作成時に親DOMノードの子供として追加する必要がある仮想ノードの配列です。
たとえばh('div', {}, [ h('h1', {}, 'Hello, World') ])仮想ノードを作成します
[
{
sel : "h1" ,
data : { } ,
children : undefined ,
text : "Hello, World" ,
elm : Element ,
key : undefined
}
] ;その.childrenプロパティとして。
.textプロパティは、テキストを所有し、 document.createTextNode()のみを使用する必要がある単一の子供のみで仮想ノードが作成されたときに作成されます。
たとえば、 h('h1', {}, 'Hello') Helloをその.textプロパティとして仮想ノードを作成します。
仮想ノードの.elmプロパティは、Snabbomによって作成された実際のDOMノードへのポインターです。このプロパティは、フックやモジュールで計算を行うのに非常に便利です。
.keyプロパティは、 .dataオブジェクトの内部にキーが提供されるときに作成されます。 .keyプロパティは、不要な場合は再現を避けるために、以前に存在していたDOMノードへのポインターを維持するために使用されます。これは、リストの並べ替えなどに非常に役立ちます。キーは、オブジェクト内の.key /値のペアとして内部に保存されるため、適切なルックアップを可能にするために文字列または数字のいずれかでなければなりません.elm
提供されれば、 .keyプロパティは兄弟の要素の中で一意でなければなりません。
たとえば、 h('div', {key: 1}, []) 1の値を持つ.keyプロパティを持つ仮想ノードオブジェクトを作成します。
Snabbdomは、低レベルの仮想DOMライブラリです。アプリケーションをどのように構築するかに関しては、選択されていません。
Snabdomを使用してアプリケーションを構築するためのいくつかのアプローチを以下に示します。
Snabbomを使用して別の方法でアプリケーションを構築している場合は、必ず共有してください。
Snabbdomに関連するパッケージは、 snabbdomキーワードでタグ付けされ、NPMに公開する必要があります。クエリ文字列keywords:snabbdomを使用して見つけることができます。
Uncaught NotFoundError: Failed to execute 'insertBefore' on 'Node':
The node before which the new node is to be inserted is not a child of this node.
このエラーの理由は、パッチ間のVNodesの再利用(コード例を参照)、Snabbdomはパフォーマンスの改善として渡された仮想Domノード内に実際のDOMノードを保存するため、パッチ間のノードの再利用はサポートされていません。
const sharedNode = h ( "div" , { } , "Selected" ) ;
const vnode1 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ "Two" ] ) ,
h ( "div" , { } , [ sharedNode ] )
] ) ;
const vnode2 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ sharedNode ] ) ,
h ( "div" , { } , [ "Three" ] )
] ) ;
patch ( container , vnode1 ) ;
patch ( vnode1 , vnode2 ) ;オブジェクトの浅いコピーを作成することで、この問題を修正できます(ここでは、オブジェクトの広がり構文を使用):
const vnode2 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ { ... sharedNode } ] ) ,
h ( "div" , { } , [ "Three" ] )
] ) ;別の解決策は、工場関数で共有VNODをラップすることです。
const sharedNode = ( ) => h ( "div" , { } , "Selected" ) ;
const vnode1 = h ( "div" , [
h ( "div" , { } , [ "One" ] ) ,
h ( "div" , { } , [ "Two" ] ) ,
h ( "div" , { } , [ sharedNode ( ) ] )
] ) ; コミュニティがフィードバックを提供することを気にするかもしれないというプル要求は、数日のそのような機会が提供された後にマージされるべきです。