外部DOM操作
サードパーティライブラリと連携する際に、DOMを自由に操作したり、状態を保持したり、コンポーネント境界を無視したりする必要がある場合があります。多くの優れたUIツールキットや再利用可能な要素はこのように動作します。
Preact(および同様にReact)では、これらのタイプのライブラリを扱うには、仮想DOMのレンダリング/差分アルゴリズムに、特定のコンポーネント(またはそれが表すDOM要素)内で実行された外部DOM操作を元に戻そうとしないように指示する必要があります。
手法
これは、コンポーネントにshouldComponentUpdate()
メソッドを定義し、false
を返すようにするだけというシンプルな方法です。
class Block extends Component {
shouldComponentUpdate() {
return false;
}
}
…または、簡略化すると
class Block extends Component {
shouldComponentUpdate = () => false;
}
このライフサイクルフックを使用して、VDOMツリーの上位で変更が発生してもPreactがコンポーネントを再レンダリングしないようにすることで、コンポーネントは、コンポーネントがアンマウントされるまで静的として扱えるルートDOM要素への参照を持つようになります。他のコンポーネントと同様に、その参照は単にthis.base
と呼ばれ、render()
から返されたルートJSX要素に対応します。
例を通して
コンポーネントの再レンダリングを「オフ」にする例を以下に示します。初期のDOM構造を生成するために、render()
はコンポーネントの作成とマウントの一部として依然として呼び出されます。
class Example extends Component {
shouldComponentUpdate() {
// do not re-render via diff:
return false;
}
componentWillReceiveProps(nextProps) {
// you can do something with incoming props here if you need
}
componentDidMount() {
// now mounted, can freely modify the DOM:
let thing = document.createElement('maybe-a-custom-element');
this.base.appendChild(thing);
}
componentWillUnmount() {
// component is about to be removed from the DOM, perform any cleanup.
}
render() {
return <div class="example" />;
}
}
デモ
実世界の例
あるいは、この手法が実際に使用されている様子をpreact-token-inputで確認できます。これは、コンポーネントをDOMへの足場として使用しますが、その後更新を無効にし、tags-inputに以降の処理を委譲します。より複雑な例としては、編集可能な<iframe>
の再レンダリングを回避するためにこの手法を使用するpreact-richtextareaがあります。