誰にとってもDOMで十分です。または、サードパーティのライブラリがDOMを変更するという事実とReactJSを調整する方法

最新のJavaScriptフレームワークとReactJSも例外ではありません。通常、DOMへの排他的アクセスが必要であり、知識のない人がこのDOMを変更した場合、DOMが好まれません。 問題は、タップ、アンプロップ、制御されたサブツリー内の別の場所への移動などを必要とする膨大な数のサードパーティライブラリ(jQueryプラグインなど)があることです。 通常、このような場合、コンソールに類似したものが表示されます。



画像



幸いなことに、この問題は非常に簡単かつ迅速に解決されます。 この投稿では、ソリューションをステップごとに説明しますが、興味がない場合、または急いでいる場合は、既製のソリューションを含むヒストグラムへのリンクまでスクロールダウンしてください。 それでは始めましょう。



誰のせいですか?



ReactJSプロジェクトでAceEditorやTinyMCEなどの非常にクールなテキストエディターを使用したいとします。 このプラグインは<textarea />要素を受け取り、ツールバーとhailatを使用して<div contenteditable />に変換します。たとえば、次のようになります。



function textarea2editor(parent){ var $parent= jQuery(parent); var $editor = jQuery('<div contenteditable/>'); $editor.css('background', "#333"); $editor.css("color", "#efefef"); $parent.find('textarea').replaceWith($editor); /*...*/ return { setText: function (text){ $editor.html(text); }, /*...*/ } }
      
      







与えられた間隔でUnixコマンドを出力するReactJSアプリケーションがあるとしましょう:



 var App = React.createClass({ render: function() { return ( <div> <textarea value={this.props.contents}/> </div> ) } }); var Component = React.render(<App contents="#./configure" />, document.body); setTimeout(function(){ Component.setProps({ contents: "#/.configure\n#make" }); }, 1000); setTimeout(function(){ Component.setProps({ contents: "#/.configure\n#make\n#make install" }); }, 2000);
      
      







もちろん、コマンドを強調表示するために上記のプラグインを使用したいと思います。このため、通常、最初にcomponentDidUpdateメソッドをコンポーネントに追加し、エディターの初期化を行います。



 componentDidMount: function(){ this.editor = textarea2editor(this.getDOMNode()); this.editor.setText(this.props.contents); }
      
      







componentDidUpdateのメソッドコンポーネントと同様に、コンポーネントが更新されるたびに<div contenteditable />のコンテンツを更新します。



  componentDidUpdate: function(){ this.editor.setText(this.props.contents); }
      
      







そして次のフィードを入手しました。

実行すると、最初のコマンドのみが「ターミナル」に表示され、残りは表示されないことがわかります。 そして、コンソールを開くと、これが起こる理由がわかります。







もちろん、ポイントは、「エディター」がReactの知識なしで<textarea />を<div contenteditable />に置き換え、Reactが混乱していることです。仮想家には<textarea />がありますが、実際の家にはありません、そのような状況でページをどのように比較して更新するかが明確ではありません。



そして何をすべきか?



幸いなことに、解決策は非常に単純ですが、すぐには思い浮かばなくなりました。 AngularJSでの私の経験は、ngNonBindableディレクティブが存在するこのソリューションで私にインスピレーションを与えました。







Reactにはそのようなものがあるのだろうかと思いました。 ドキュメントには(直接)これが記載されていませんが、ブール値を返すshouldComponentUpdateメソッドについて言及しており、falseの場合、Reactはコンポーネントだけでなくそのサブツリー全体も更新しません。 つまり、単にcomponentWillUpdate、componentWillReceiveProps、renderなどのメソッドを呼び出すことはありません。 この方法は最適化ツールとして提案されていますが、待ってください。renderを呼び出さない場合、仮想DOMのコンポーネントのサブツリーは変更されないため、この仮想サブツリーと対応する実際のDOMの差分は原則として不要です。つまり、この「最適化」方法を使用すると、Reactに支配的なDOMの特定の部分を無視させることができますか? 可能ですが、コンポーネントに追加すると:



 shouldComponentUpdate: function (){ return false; }
      
      





エラーは消えますが、「ターミナル」は更新されません。 実際、Reactにコンポーネント全体ではなく<textarea />のみを無視させるようにする必要があります。このためにRenderOnceTextareaを実際に記述する必要があるので、React.DOMからコンポーネントを使用する場合はいつでも



実際には、より良い解決策があります-ReactIgnoreコンポーネントを記述し、常にその子を返し、shouldComponentUpdateで常にfalseを返します。



 var ReactIgnore = React.createClass({ displayName: 'ReactIgnore', shouldComponentUpdate: function(){ return false; }, render: function (){ return React.Children.only(this.props.children); } });
      
      







これが有効なフィードです。



tl; dr別名histへのリンク



ReactIgnoreをプロジェクトからコピーし、それを履歴(ahtung、ES6 Harmony)として投稿し、健康に使用します。



All Articles