Reactを数日間読んでいます。私が見ているもののほとんどは理解できますが、それを書く能力に完全には自信がありません。 jQueryを介してすべてのhtml生成を行い、要素を相互に追加する小さなWebアプリに取り組んでいます。これをReactで再構築したいと思います。この JSFiddle は、私が取り組んでいる種類の小さな例です。
JS:
function remove() {
this.remove();
}
function timed_append_new_element() {
setTimeout(function () {
var added_content = $("<span />", {
class: "added_content",
text: "Click to close",
click: remove
});
container.append(added_content);
}, 3000);
}
function append_new_element() {
var added_content = $("<span />", {
class: "timed_added_content",
text: "Click to close",
click: remove
});
container.append(added_content);
}
var container = $("<div />", {
class: "container"
});
var header = $("<span />", {
class: "header",
text: "jQuery to React.js Header"
});
var add_button = $("<button />", {
class: "add_button",
text: "Add Element",
click: append_new_element
});
var timed_add_button = $("<button />", {
class: "add_button",
text: "Add Element in 3 seconds",
click: timed_append_new_element
});
container.append(header);
container.append(add_button);
container.append(timed_add_button);
$("body").append(container);
優れたReactアプリケーションの構築に役立つ基本的な考え方がいくつかあります。
UIはデータの関数でなければなりません
多くの「jQueryスープ」スタイルのアプリケーションでは、アプリケーションのビジネスロジック、アプリのデータ、およびUI相互作用コードはすべて混在しています。これにより、これらの種類のアプリケーションのデバッグが困難になり、特に成長が困難になります。 Reactは、多くの最新のクライアント側アプリケーションフレームワークと同様に、UIはデータの単なる表現であるという考えを強制します。 UIを変更する場合は、データを変更し、フレームワークがUIを更新するために使用するバインディングシステムを許可する必要があります。
Reactでは、各コンポーネントは(理想的には)2つのデータの関数です。コンポーネントインスタンスに渡されるpropertiesとstateコンポーネントが内部で管理すること。同じプロパティ(または「プロパティ」)と状態が与えられた場合、コンポーネントは同じ方法でレンダリングする必要があります。
これは具体的な例のない少し抽象的な概念になる可能性があるため、今から進むときに念頭に置いてください。
DOMに触れないでください
Reactでは、他のデータバインドフレームワークよりもさらに、DOMを可能な限り直接操作しないでください。 Reactは内部で異なるアルゴリズムを持つ仮想DOMを使用して実際のDOMで動作するため、Reactの多くのパフォーマンスと複雑さの特性が可能です。独自のDOM操作を行うコンポーネントを作成するときはいつでも、Reactの仮想DOM機能を使用して同じ機能をより慣用的に作成できるかどうかを自問する必要があります。
もちろん、DOMにアクセスする必要がある場合や、Reactで再構築せずにjQueryプラグインを組み込みたい場合があります。このような場合は、Reactが優れた コンポーネントライフサイクルフック を提供します。これを使用して、Reactのパフォーマンスが低下しすぎないようにすることができます(場合によっては、プレーン破壊からのコンポーネント)。
DOMを操作しないことは、上記の「データの関数としてのUI」と密接に関係しています。
データフローを反転します
大きなReactアプリケーションでは、どのサブコンポーネントが特定のアプリケーションデータを管理しているかを追跡するのが難しい場合があります。このため、Reactチームは、データ操作ロジックを中央の場所に保管することを推奨しています。これを行う最も簡単な方法は、コールバックを子コンポーネントに渡すことです。 Facebookで開発されたFluxというアーキテクチャもあります。これは 独自のWebサイト です。
構成可能なコンポーネントの作成
多くの場合、状態のいくつかの部分やUIロジックのいくつかの部分を管理する大きなコンポーネントを作成するのは魅力的です。可能な場合(および合理的な範囲内で)、大きなコンポーネントを単一のデータまたはUIロジックで動作する小さなコンポーネントに分割することを検討する必要があります。これにより、アプリケーションの各部分を簡単に拡張および移動できます。
可変データに注意してください
コンポーネントの状態は、コンポーネント内からのthis.setState
の呼び出しを介してのみ更新する必要があるため、変更可能なデータには注意が必要です。これは、複数の関数(またはコンポーネント!)が同じ目盛りで可変オブジェクトを更新する可能性がある場合、二重に当てはまります。 Reactは状態の変更をバッチ処理しようとする場合があり、更新を失う可能性があります。 Eliseu Monarのコメントで述べたように、変更可能なオブジェクトを変更する前に、それらのクローンを作成することを検討してください。 Reactには 不変性ヘルパー があります。
別のオプションは、変更可能なデータ構造を直接状態に維持することをまったくしないことです。上記のFluxパターンは、このアイデアに対する興味深い見解です。
Reactサイトには Reactを考える という素晴らしい記事があります。これは、アイデアやモックアップをどのようにしてReactアプリケーションに変えるかを説明しています。 、そしてそれを超えることを強くお勧めします。具体的な例として、提供したコードを見てみましょう。基本的に、管理するデータは1つだけです。container
要素内に存在するコンテンツのリストです。 UIに対するすべての変更は、そのデータの追加、削除、および変更によって表すことができます。
上記の原則を適用すると、最終的なアプリケーションは次のようになります。
/** @jsx React.DOM */
var Application = React.createClass({
getInitialState: function() {
return {
content: []
};
},
render: function() {
return (
<div className="container">
<span className="header">jQuery to React.js Header</span>
<button className="add_button"
onClick={this.addContent}>Add Element</button>
<button className="add_button"
onClick={this.timedAddContent}>Add Element in 3 Seconds</button>
{this.state.content.map(function(content) {
return <ContentItem content={content} removeItem={this.removeItem} />;
}.bind(this))}
</div>
);
},
addContent: function() {
var newItem = {className: "added_content", text: "Click to close"},
content = this.state.content,
newContent = React.addons.update(content, {$Push: [newItem]});
this.setState({content: newContent});
},
timedAddContent: function() {
setTimeout(function() {
var newItem = {className: "timed_added_content", text: "Click to close"},
content = this.state.content,
newContent = React.addons.update(content, {$Push: [newItem]});
this.setState({content: newContent});
}.bind(this), 3000);
},
removeItem: function(item) {
var content = this.state.content,
index = content.indexOf(item);
if (index > -1) {
var newContent = React.addons.update(content, {$splice: [[index, 1]]});
this.setState({content: newContent});
}
}
});
var ContentItem = React.createClass({
propTypes: {
content: React.PropTypes.object.isRequired,
removeItem: React.PropTypes.func.isRequired
},
render: function() {
return <span className={this.props.content.className}
onClick={this.onRemove}>{this.props.content.text}</span>;
},
onRemove: function() {
this.props.removeItem(this.props.content);
}
});
React.renderComponent(<Application />, document.body);
this JSFiddle で動作中のコードを見ることができます: http://jsfiddle.net/BinaryMuse/D59yP/
アプリケーションは、(状態で)Application
という配列を管理するcontent
というトップレベルコンポーネントと、UIを表すContentItem
というコンポーネントの2つのコンポーネントで構成されています。およびその配列からの単一アイテムの動作。 Application
のrender
メソッドは、コンテンツ配列内の各アイテムのContentItem
要素を返します。
注目すべきことの1つは、content
配列内の値を管理するためのすべてのロジックがApplication
コンポーネントで処理されることです。 ContentItem
コンポーネントには、referenceがApplication
のremoveItem
メソッドに渡され、クリックするとContentItem
が委任されます。これにより、最上位コンポーネント内で状態を操作するためのすべてのロジックが保持されます。