ReactJS 15.0.2チュートリアル

Disqus、LiveFyre、Facebookなどのリソースによって提供されるリアルタイムコメントモジュールの単純化された類似物である、シンプルだが現実的なブログコメントモジュールを作成します。







私達は提供します:









また実装されます:









最終版



GitHubリンク







サーバー起動



マニュアルを開始する前に、サーバーを起動する必要があります。 これは、データの受信と保存に使用する単純なAPIです。 すでにいくつかのインタプリタ言語で作成しており、必要最小限の機能を備えています。 ソースコードに慣れる必要なものがすべて含まれているzipアーカイブダウンロードできます。







はじめに



このガイドでは、できる限りシンプルにすべてを実装しようとします。 前述のアーカイブには、作業を継続するHTMLファイルがあります。 コードエディタでpublic / index.htmlファイルを開きます。 次のようになります。







<!-- index.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>React Tutorial</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js"></script> </head> <body> <div id="content"></div> <script type="text/babel" src="scripts/example.js"></script> <!--      --> <script type="text/babel"> //      script,  scripts/example.js //       . </script> </body> </html>
      
      





マニュアルのすべてのJavaScriptコードは、scriptタグに記述します。 ライブリロードがないため、変更を保存するたびにブラウザでプロジェクトページを更新する必要があります。 ブラウザでリンクhttp:// localhost:3000を開くと、結果を追跡できます(サーバーの起動後)。 コードを変更せずに初めてリンクを開くと、コメントモジュールの最終バージョンが表示されます。 開始するには、プロジェクトの最終バージョン「scripts / example.js」のコードをロードする最初のスクリプトタグを削除する必要があります







注:プロジェクトでjQueryを使用して、今後のAjaxリクエストのコードを簡素化しますが、これはReactライブラリではありません







最初のコンポーネント



Reactは、モジュラーで構成可能なフレームワークです。 このプロジェクトは、次の構造にあるいくつかのコンポーネントで構成されています。









CommentBoxコンポーネントを作成します 。これは、出力の通常の<div>



タグになります。







 // tutorial1.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> Hello, world! I am a CommentBox. </div> ); } }); ReactDOM.render( <CommentBox />, document.getElementById('content') );
      
      





Reactクラスの名前が大文字になっている場合、HTML要素の名前は小文字で始まることに注意してください。







JSX構文



最初に目を引くのは、提供されているJavaScriptコードのXMLに似た構文です。 出力で純粋なJavaScriptを生成する単純なプリコンパイラを使用します。







 // tutorial1-raw.js var CommentBox = React.createClass({displayName: 'CommentBox', render: function() { return ( React.createElement('div', {className: "commentBox"}, "Hello, world! I am a CommentBox." ) ); } }); ReactDOM.render( React.createElement(CommentBox, null), document.getElementById('content') );
      
      





プリコンパイラの使用はオプションであり、純粋なJavaScriptで記述できますが、ガイドではJSX構文を使用します。 詳細については、 JSX構文の記事を参照してください







コードで何が起こるか



いくつかのメソッドを持つJavaScriptオブジェクトをReact.createClass()渡して、新しいReactコンポーネントを作成します。 渡される最も重要なメソッドはrenderと呼ばれ、最終的にHTMLに変換されるReactコンポーネントのツリーを返します。







<div>



タグは実際のDOMノードではなく、これはReact <div>



コンポーネントの実装です。 Reactが処理方法を知っているマーカーまたはデータの断片を考慮することができます。 ReactはXSSの脆弱性に関して安全です。







HTMLコードを返す必要はありません。 自分(または他の誰か)が作成したコンポーネントツリーを返すことができます。 このアプローチにより、Reactは構成可能になります。これは、よく維持され、適切に設計されたフロントエンドアーキテクチャの重要な機能です。







ReactDOM.render()は、ルートコンポーネントのインスタンスを作成し、フレームワークを起動し、2番目の引数で渡されたDOM要素にマークアップを挿入します。







ReactDomオブジェクトには、DOMを操作するためのメソッドが含まれていますが、 Reactオブジェクトには、 React Nativeなどの他のライブラリで使用されるルートメソッドが含まれています。







ReactDOM.renderの呼び出しは、すべてのコンポーネントが宣言された後に行う必要があります。 これは重要です。







組み合わせたコンポーネント



通常の<div>



なるCommentListおよびCommentFormのスケルトンを作成します。 これらの2つのコンポーネントをファイルに追加し、前の例のCommentBoxReactDOM.renderをそれぞれの場所に残します







 // tutorial2.js var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> Hello, world! I am a CommentList. </div> ); } }); var CommentForm = React.createClass({ render: function() { return ( <div className="commentForm"> Hello, world! I am a CommentForm. </div> ); } });
      
      





次に、 CommentBoxコンポーネントを変更して、新しいコンポーネント(「// new」とマークされた行)を使用します。







 // tutorial3.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> //new start <h1>Comments</h1> <CommentList /> <CommentForm /> //new end </div> ); } });
      
      





作成したHTMLタグとコンポーネントの組み合わせに注意してください。 HTMLコンポーネントは、私たちが発表したもののような標準のReactコンポーネントですが、1つだけ違いがあります。 JSXプリプロセッサは、 React.createElement(tagName)式のHTMLタグを自動的に書き換え、他のすべてをそのままにします。 これは、グローバル名前空間の目詰まりを防ぐために必要です。







詳細の使用



親コンポーネントによって送信されるデータに依存するコメントコンポーネントを作成します。 親から渡されたデータは、子コンポーネントのプロパティとして利用できます。 プロパティへのアクセスはthis.propsを介して行われます。 詳細を使用して、 CommentListからCommentに渡されたデータを読み取り、マークアップを表示できます。







 // tutorial4.js var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {this.props.children} </div> ); } });
      
      





JavaScript式をJSX内で中括弧で囲むことにより、テキストまたはReactコンポーネントをツリーに追加できます。 this.propsのキーとしてコンポーネントに渡された名前付き属性、およびthis.props.childrenなどのネストされた要素にアクセスします。







コンポーネントのプロパティ



Commentsの宣言されたコンポーネントができたので、著者の名前とコメントのテキストを渡します。 これにより、各コメントに同じコードを再利用できます。 次に、 CommentListコンポーネントにいくつかのコメントを追加します。







 // tutorial5.js var CommentList = React.createClass({ render: function() { return ( <div className="commentList"> //new start <Comment author="Pete Hunt">This is one comment</Comment> <Comment author="Jordan Walke">This is *another* comment</Comment> //new end </div> ); } });
      
      





CommentListの親コンポーネントからCommentの子コンポーネントにデータを渡す方法に注目してください。 たとえば、最初のCommentに Pete Hunt (属性を介して)を渡し、 これは (XMLに似た子ノードを介して)1つの要素です。 前述のように、 Commentコンポーネントはthis.props.authorおよびthis.props.childrenを介してこれらのプロパティにアクセスします。







マークダウンマークアップを追加



マークダウンは、テキストをフォーマットする便利な方法です。 たとえば、アスタリスクでラップされたテキストには、出力に下線が引かれます。







このチュートリアルでは、マークダウンされたサードパーティライブラリを使用します。これ 、Markdownマークアップを純粋なHTMLに変換します。 このライブラリを既にHTMLファイルに含めているため、使用を開始できます。 Markdownマークアップに基づいてコメントテキストを変換して出力します。







 // tutorial6.js var Comment = React.createClass({ render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> {marked(this.props.children.toString())} // new </div> ); } });
      
      





ここで行ったのは、 マークされたライブラリを呼び出すことだけです。 これで、 this.props.childrenをReactのようなテキストから、 マークされた理解できる通常の行に変換する必要があるため、具体的にtoString()関数を呼び出します。







しかし、問題があります! ブラウザで処理されたコンポーネントは、「 <p>



これは<em>



別の</em>



コメント</p>



」のようになります。 すべてのタグをHTMLテキストのマークアップに変換する必要があります。







したがって、ReactはXSS攻撃からユーザーを保護します。 これを回避する方法は次のとおりです。







 // tutorial7.js //new start var Comment = React.createClass({ rawMarkup: function() { var rawMarkup = marked(this.props.children.toString(), {sanitize: true}); return { __html: rawMarkup }; }, //new end render: function() { return ( <div className="comment"> <h2 className="commentAuthor"> {this.props.author} </h2> <span dangerouslySetInnerHTML={this.rawMarkup()} /> //new </div> ); } });
      
      





これは純粋なHTMLでの作業を意図的に複雑にする特別なAPIですが、 markedについて例外を作成します。







注意!:このような例外を使用すると、 マークされたライブラリのセキュリティに完全に依存します。 これを行うには、2番目の引数をsenitize:true渡します。これには、HTMLタグのクリアが含まれます。







データモデルを接続する



ここまで、コードから直接コメントを挿入しました。 ここで、JSONオブジェクトをコメントリストに変換してみましょう。 次に、サーバーからそれらを取得しますが、ここではコードに次の行を追加します。







 // tutorial8.js var data = [ {id: 1, author: "Pete Hunt", text: "This is one comment"}, {id: 2, author: "Jordan Walke", text: "This is *another* comment"} ];
      
      





次に、このオブジェクトをCommentListに渡して、モジュール性を観察する必要があります。 propsメソッドを使用して、 CommentBoxRenderDOM.render()を変更して、 CommentListコンポーネントにデータを転送します。







 // tutorial9.js var CommentBox = React.createClass({ render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.props.data} /> //new <CommentForm /> </div> ); } }); ReactDOM.render( <CommentBox data={data} />, //new document.getElementById('content') );
      
      





CommentListコンポーネントでデータが利用可能になったので、コメントを動的に表示してみましょう。







 // tutorial10.js var CommentList = React.createClass({ render: function() { //new start var commentNodes = this.props.data.map(function(comment) { return ( <Comment author={comment.author} key={comment.id}> {comment.text} </Comment> ); }); //new end return ( <div className="commentList"> {commentNodes} // new </div> ); } });
      
      





できた!







サーバーからコメントを受け取る



コードに含まれるコメントをサーバーからのデータに置き換えます。 これを行うには、以下に示すように、 データ属性をurlに置き換えます。







 // tutorial11.js ReactDOM.render( <CommentBox url="/api/comments" />, // new document.getElementById('content') );
      
      





ご注意 この時点で、コードは機能しません。







反応状態



これまで、各コンポーネントはパラメータに基づいて一度描画され、 小道具は変更されません。つまり、親から送信され、所有者のままになります。 相互作用を整理するために、コンポーネントに可変プロパティを追加します。 this.stateはコンポーネントに対してプライベートであり、 this.setState()を呼び出して変更できます。 プロパティを更新すると、コンポーネントは再描画されます。







render()メソッドは、関数this.propsthis.stateのように宣言的に記述されます。

Reactは、サーバーとユーザーインターフェイスでデータの一貫性を確保します。







サーバーがデータを送信するとき、インターフェイスのコメントを変更する必要があります。 CommentBoxコンポーネントに別個のパラメーターを使用してコメント配列を追加します。







 // tutorial12.js var CommentBox = React.createClass({ //new start getInitialState: function() { return {data: []}; }, //new end render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> // new <CommentForm /> </div> ); } });
      
      





getInitialState()は、コンポーネントのライフサイクル中に1回実行され、コンポーネントの初期状態を設定します。







更新ステータス



コンポーネントを作成した後、サーバーからJSONを取得し、コンポーネントのデータを更新してインターフェースに表示します。 非同期サーバーリクエストの場合、jQueryを使用します。 データは、最初に起動したサーバー(comments.jsonに保存)に既にあります。 サーバーからデータを受信すると、 this.state.dataには以下が含まれます。







 [ {"id": "1", "author": "Pete Hunt", "text": "This is one comment"}, {"id": "2", "author": "Jordan Walke", "text": "This is *another* comment"} ]
      
      





 // tutorial13.js var CommentBox = React.createClass({ getInitialState: function() { return {data: []}; }, //new start componentDidMount: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, //new end render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } });
      
      





componentDidMountメソッドは、コンポーネントの最初のレンダリング後にReactによって自動的に呼び出されます。 this.setState()メソッドは、動的に更新を行います。 古いコメント配列をサーバーからの新しい配列に置き換え、インターフェースは自動的に更新されます。 このため、リアルタイムで更新を追加するには、マイナーな編集が​​必要です。 簡単にするために、 ポーリングテクノロジー(Frequent Requests)を使用しますが、将来はWebSocketsまたはその他のテクノロジーを簡単に使用できます。







 // tutorial14.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { // new $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, // new getInitialState: function() { return {data: []}; }, componentDidMount: function() { //new start this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); //new end }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm /> </div> ); } }); ReactDOM.render( <CommentBox url="/api/comments" pollInterval={2000} />, // new document.getElementById('content') );
      
      





ここでは、AJAXリクエストを別のメソッドに移動し、コンポーネントの最初の読み込み後と2秒ごとに呼び出しを開始します。 ここで、ブラウザでコメントページを開き、 comments.jsonファイル(サーバーのルートディレクトリ内)に変更を加えます。 2秒以内にページに変更が表示されます。







新しいコメントを追加



次に、コメントフォームを作成します。 CommentFormコンポーネントは、ユーザーにコメントの名前とテキストを要求し、さらにコメントを保存するためにサーバーにリクエストを送信する必要があります。







 // tutorial15.js var CommentForm = React.createClass({ render: function() { return ( //new start <form className="commentForm"> <input type="text" placeholder="Your name" /> <input type="text" placeholder="Say something..." /> <input type="submit" value="Post" /> </form> //new end ); } });
      
      





制御されたコンポーネント



従来のDOMでは、 入力要素が描画されてから、ブラウザがその値を設定します。 その結果、DOM値はコンポーネント値とは異なります。 ビューの値がコンポーネントの値と異なる場合、それは悪いです。 Reactでは、コンポーネントは、その初期化時だけでなく、常にビューに対応する必要があります。







したがって、 this.stateを使用してユーザー入力を保存します。 作成テキストの 2つのプロパティを使用して初期状態の状態を宣言し、空の文字列の値を割り当てます。 <input>



要素で、 値の 状態を valueパラメーターに割り当て、 onChangeハンドラーをその上に配置します。 value属性値が設定されたこの<input>



要素は、制御コンポーネントと呼ばれます。 コントロールされたコンポーネントの詳細については、 フォームの記事をご覧ください







 // tutorial16.js var CommentForm = React.createClass({ //new start getInitialState: function() { return {author: '', text: ''}; }, handleAuthorChange: function(e) { this.setState({author: e.target.value}); }, handleTextChange: function(e) { this.setState({text: e.target.value}); }, //new end render: function() { return ( <form className="commentForm"> //new start <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange} /> <input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange} /> //new end <input type="submit" value="Post" /> </form> ); } });
      
      





イベント



ReactイベントハンドラーはcamelCase命名規則を使用します。 2つの<input>



要素にonChangeハンドラーを掛けました 。 ユーザーが<input>



フィールドにデータを<input>



ので、イベントハンドラーはコールバックを行い、コンポーネントの値を変更します。 その後、コンポーネントの現在の値を反映するために、 入力値が更新されます。







フォーム送信



フォームをインタラクティブにしましょう。 ユーザーがフォームを送信した後、フォームをクリアし、サーバーにリクエストを送信し、コメントのリストを更新する必要があります。 最初に、フォームデータを取得してクリアします。







 // tutorial17.js var CommentForm = React.createClass({ getInitialState: function() { return {author: '', text: ''}; }, handleAuthorChange: function(e) { this.setState({author: e.target.value}); }, handleTextChange: function(e) { this.setState({text: e.target.value}); }, //new start handleSubmit: function(e) { e.preventDefault(); var author = this.state.author.trim(); var text = this.state.text.trim(); if (!text || !author) { return; } // TODO:     this.setState({author: '', text: ''}); }, //new end render: function() { return ( <form className="commentForm" onSubmit={this.handleSubmit}> // new <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange} /> <input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange} /> <input type="submit" value="Post" /> </form> ); } });
      
      





フォームにonSubmitハンドラーをハングアップします。これにより、フォームに正しいデータが入力されて送信されたときにクリアされます。







preventDefault()呼び出して 、ブラウザがデフォルトでフォームを送信しないようにします。







パラメーターとしてのコールバック



ユーザーがコメントを送信したら、コメントシートを更新して新しいものを追加する必要があります。 CommentBoxはコメントのリストを管理するため、このすべてのロジックをCommentBoxに実装することは理にかなっています。







子コンポーネントから親に渡す必要があります。 これは、親renderメソッドを介して行い、新しいコールバック( handleCommentSubmit )を子に渡し 、子コンポーネントのonCommentSubmitイベントに関連付けます。 イベントが発生するたびに、コールバック関数が呼び出されます:







 // tutorial18.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, //new start handleCommentSubmit: function(comment) { // TODO:        }, //new end getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> // new </div> ); } });
      
      





CommentBoxコンポーネント onCommentSubmitパラメーターを介してCommentFormコンポーネントへのコールバック関数へのアクセスを許可したので 、ユーザーがフォームを送信すると、 CommentFormコンポーネントはコールバック関数を呼び出すことができます。







 // tutorial19.js var CommentForm = React.createClass({ getInitialState: function() { return {author: '', text: ''}; }, handleAuthorChange: function(e) { this.setState({author: e.target.value}); }, handleTextChange: function(e) { this.setState({text: e.target.value}); }, handleSubmit: function(e) { e.preventDefault(); var author = this.state.author.trim(); var text = this.state.text.trim(); if (!text || !author) { return; } this.props.onCommentSubmit({author: author, text: text}); // new this.setState({author: '', text: ''}); }, render: function() { return ( <form className="commentForm" onSubmit={this.handleSubmit}> <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange} /> <input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange} /> <input type="submit" value="Post" /> </form> ); } });
      
      





コールバック関数が用意できたので、サーバーにデータを送信し、コメントシートを更新するだけです。







 // tutorial20.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, handleCommentSubmit: function(comment) { //new start $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); //new end }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });
      
      





最適化:楽観的な更新



アプリケーションの準備は整っていますが、サーバーへのリクエストが完了するのを待っており、ページにコメントが表示されると視覚的に遅くなります。 サーバーへのリクエストが完了するのを待たずに、すぐにコメントをリストに追加できます。これはほぼ瞬時に行われます。







 // tutorial21.js var CommentBox = React.createClass({ loadCommentsFromServer: function() { $.ajax({ url: this.props.url, dataType: 'json', cache: false, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); }.bind(this) }); }, handleCommentSubmit: function(comment) { //new start var comments = this.state.data; // Optimistically set an id on the new comment. It will be replaced by an // id generated by the server. In a production application you would likely // not use Date.now() for this and would have a more robust system in place. comment.id = Date.now(); var newComments = comments.concat([comment]); this.setState({data: newComments}); //new end $.ajax({ url: this.props.url, dataType: 'json', type: 'POST', data: comment, success: function(data) { this.setState({data: data}); }.bind(this), error: function(xhr, status, err) { this.setState({data: comments}); // new console.error(this.props.url, status, err.toString()); }.bind(this) }); }, getInitialState: function() { return {data: []}; }, componentDidMount: function() { this.loadCommentsFromServer(); setInterval(this.loadCommentsFromServer, this.props.pollInterval); }, render: function() { return ( <div className="commentBox"> <h1>Comments</h1> <CommentList data={this.state.data} /> <CommentForm onCommentSubmit={this.handleCommentSubmit} /> </div> ); } });
      
      





おめでとうございます!



いくつかの簡単な手順でコメントモジュールを作成しました。 Reactを使用する理由の詳細をご覧になるかAPIに直接進んでコードの記述を開始してください! 頑張って








All Articles