VueでComponentを再描画をしたい場合の2つの方法の比較
やりたいこと
VueでComponentの再描画を行いたいときのベストな方法について調べてみました。調べて出てきたkeyを使う方法、forceUpdateを使う方法についてどちらが良いのかを比較しています。また調べる過程でVueの内部でどのように処理されているかを知り今後に活かしたいと思っています。
注意
Vue2の内容であることにご注意ください。
再描画を実装する前に
2番目に挙げた参考文献でも記述がありますが、再描画がベストな方法になることはそこまで多くないのではないかと思っています。特にObjectやArrayに対してデータの変更を行なった後にうまくいかない場合は下記を再確認することをお勧めします!
方法1.keyを使う方法
keyの説明はこちらで、和訳をそのまま引用すると下記です。
このkey特別な属性は、主に、新しいノードのリストと古いリストを比較するときに VNode を識別するための Vue の仮想 DOM アルゴリズムのヒントとして使用されます。キーがない場合、Vue は要素の移動を最小限に抑えるアルゴリズムを使用し、可能な限り同じタイプの要素をその場でパッチ/再利用しようとします。キーがある場合、キーの順序変更に基づいて要素を並べ替え、キーが存在しなくなった要素は常に削除/破棄されます。
同じ共通の親の子は一意のキーを持つ必要があります。重複するキーはレンダリング エラーの原因になります。
また、要素/コンポーネントを再利用するのではなく、強制的に置き換えるためにも使用できます。これは、次のような場合に役立ちます。
上記で言及されている『要素/コンポーネントを再利用するのではなく、強制的に置き換えるためにも使用できる』という部分はソースコードでtransitionに記述があります。isSameChild
でkeyとtagが一致したものを同じ子要素として判定し、render
の中で!isSameChild
の条件で古いchildが新しいものと置き換えられる流れとなっています。新しいものと置き換える際に後述するforceUpdate
を呼んでいます。
方法2.forceUpdateを使う方法
forceUpdateの説明はこちらで、和訳をそのまま引用すると下記です。
Vue インスタンスを強制的に再レンダリングします。これはすべての子コンポーネントに影響するわけではなく、インスタンス自体とスロット コンテンツが挿入された子コンポーネントにのみ影響することに注意してください。
forceUpdateはソースコードではlifecycleの部分で定義されています。その後はwatcherで定義されているWatcher
のupdate
が呼ばれsync
がtrueの場合はrun
を実行し、それ以外の場合はqueueWatcher
に渡されるようになっています。
調べた結果
挙動の観点で考えると、keyを使った場合に内部でforceUpdateを呼んでいたのでどちらでもいいという結論になりました。他者にソースコードを読んでもらう観点で考えると、keyを変更して再描画を行う場合に前提としてkeyを変更した場合に再描画されるという知識が必要となりますが、forceUpdateの場合は関数名を読めば直感的に分かるのでforceUpdateの方が良いのではないかと思います。微々たる差ですが新しくどちらかを選ぶとなると個人的にはforceUpdateの方が良いのではないかと思っています。
参考文献
Discussion