やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

HTML要素の配列をbodyへ挿入しリアクティブに更新したい《VanJS》

 配列の所でハマりましたが、解決したので書き残します。

前回

やりたいこと

const htmls = van.state([HTML要素, ...])
htmls.val = [新しいHTML要素, ...]

 複数のHTML要素をまとめてリアクティブに更新したいです。

 たとえばマークダウンを入力し、それをHTMLにパースして、HTML要素を配列にし、それをリアクティブに更新する場合などを想定しています。

コード

const {div,h1,p} = van.tags
const htmls = van.state([h1('van.state()'), p('本文。')])
van.add(document.body, ()=>div(htmls.val)) // OK
htmls.val = [h1('van.state()書き換え'), p('本文を書き換えた。')]

 ポイントは以下。

  • van.state([])を使う(vanX.reactive([])はダメ)
  • リアクティブにしたい要素や属性があるときは関数で返す
  • 要素配列をvan.addしたいときはdivに配列を渡してから返す

See the Pen Untitled by ytyaru (@ytyaru) on CodePen.

失敗例

van.add(document.body, ...htmls.val) // リアクティブでない
van.add(document.body, htmls) // NG [object HTMLHeadingElement],[object HTMLParagraphElement]
van.add(document.body, ()=>htmls.val) // NG [object HTMLHeadingElement],[object HTMLParagraphElement]
van.add(document.body, ()=>...htmls.val) // NG SyntaxError: Unexpected token '...'

 vanX.reactive()を使って以下のように書いてもダメでした。

const html2s = vanX.reactive([h1('vanX.reactive()'), p('本文。')])
//van.add(document.body, html2s) // NG [object HTMLHeadingElement][object HTMLParagraphElement]
//van.add(document.body, vanX.stateFields(html2s)) // NG [object Object]
//van.add(document.body, vanX.stateFields(html2s).val) // NG 何も表示されない
//van.add(document.body, vanX.list(div, html2s, (v)=>v)) // NG [object Object][object Object]

 返す型が違います。van.state([]).valは配列を返しますが、vanX.stateFields(vanX.reactive([]))はオブジェクト型を返します。

 van.add()の第二引数以降には追加したいHTML要素を渡すべきです。HTML要素を含んだ配列やオブジェクトなら展開する必要があります。

 vanX.list()を使えばvanX.reactive([el,...])でもイケるかと思いましたが、ダメでした。よくわかりません。

van.state()vanX.reactive()の違い

 両者ともリアクティブにする状態を生成しますが、その構造が違います。

const htmls = [van.tags.h1('H1'),van.tags.p('P')]
const s1 = van.state(htmls)
console.log(s1)
{i: Array(2), u: Array(2), l: Array(0), o: Array(0)}
const htmls = [van.tags.h1('H1'),van.tags.p('P')]
const r = vanX.reactive(htmls)
const s2 = vanX.stateFields(r)
console.log(s2)
{
    "0": {
        "i": {},
        "u": {},
        "l": [],
        "o": []
    },
    "1": {
        "i": {},
        "u": {},
        "l": [],
        "o": []
    }
}

 vanX.reactive()のほうは配列でなくオブジェクトに変換されてしまうようです。配列のインデックス0,1がオブジェクトのキーになっています。

 変数名がi,u,l,oなど短い一字に変換されています。minifyしたライブラリ*.min.jsを使ったせいです。minでないライブラリファイルに差し替えると、ちゃんとした名前が見れます。それが以下です。val, oldValvan.state()のプロパティとして公式ドキュメントに書いてあったので、それに対応する値でしょう。

{
    "_val": [
        {},
        {}
    ],
    "_oldVal": [
        {},
        {}
    ],
    "_bindings": [],
    "_listeners": []
}

 デバッガで見るとわかりますが、値はProxyクラスにされて返却されていました。詳しくは気にしなくて大丈夫でしょう。

結論

 VanJSで要素の配列をリアクティブにbodyへ挿入したいときは、次のようにする。

  1. van.state()を使う
  2. div()の引数に要素配列を渡す
  3. 2をvan.add()に渡す
const {div,h1,p} = van.tags
const htmls = van.state([h1('見出し'), p('本文。')])
van.add(document.body, ()=>div(htmls.val))
htmls.val = [h1('見出し書き換え'), p('本文を書き換えた。')]