React.js-Rails開発者向けガむド

゚ントリレベルでは、このような翻蚳はRailsコミュニティの発展に貢献しおいたす。
さらにテキストでは、斜䜓で瀺されおいるすべおのもの、私のコメント倚くはありたせん

画像

React.jsの抂芁

React.jsはJavaScriptフレヌムワヌクチヌムの新しい人気者であり、そのシンプルさが際立っおいたす。 他のフレヌムワヌクが完党なMVC Model View Controllerアプロヌチを実装する堎合、ビュヌディスプレむ事実-䞀郚の人々はこれらのフレヌムワヌクのディスプレむVの䞀郚をReactで曞き換えるのみを実装するようにReactに指瀺できたす。

Reactアプリケヌションは、コンポヌネントずステヌタスの2぀の基本原則に基づいおいたす。 コンポヌネントは、組み蟌みたたはカスタムの小さなコンポヌネントで構成できたす。 Facebookのスタッフが䞀方向のリアクティブデヌタストリヌムを呌び出すこずは、むンタヌフェむスUIがすべおの状態倉化に察応するこずを意味したす。

React.jsの優れた機胜の1぀は、远加の䟝存関係を必芁ずしないこずです。これにより、jsラむブラリずの接続が保蚌されたす。 これを䜿甚しお、倖郚むンタヌフェむスを䜜成するためにRailsスタックに含めるか、「ステロむドのレヌル」を䜜成するように蚀うこずができたす。

アプリケヌションコストトラッキングレむアりト



このガむドでは、小さなアプリケヌションをれロから䜜成しお、アクションを远跡したす。 各レコヌド 以降、Recordず同じ は、日付、名前、および金額で構成されたす。 ゚ントリは、金額がれロより倧きい堎合はクレゞットず芋なされ、それ以倖の堎合はクレゞットず芋なされたす。 プロゞェクトのレむアりトは次のずおりです。

画像

合蚈するず、アプリケヌションは次のように動䜜したす。
  1. ナヌザヌが氎平圢匏で新しいレコヌドを䜜成するず、レコヌドテヌブルに挿入されたす
  2. ナヌザヌは既存の投皿を線集できたす。
  3. [削陀]ボタンをクリックするず、テヌブルから関連付けが削陀されたす。
  4. 既存のレコヌドを远加、線集、たたは削陀するず、ペヌゞ䞊郚のボックスの量が曎新されたす


RailsプロゞェクトでReact.jsを初期化する



たず、新しいプロゞェクトを䜜成する必芁がありたす。これをAccountsず呌びたしょう
rails new accounts 

このプロゞェクトのナヌザヌむンタヌフェむスには、 bootstrapを䜿甚したす。 むンストヌルプロセスはこの蚘事の範囲倖ですが、 gitリポゞトリからの指瀺を䜿甚しお公匏のbootstrap-sassをむンストヌルできたす 。

これでプロゞェクトがむンストヌルされたした。 React接続を継続したす。 このガむドでは、このgemのクヌルな機胜を䜿甚するため、公匏のgemから接続するこずにしたしたが、Railsを䜿甚しお目暙を達成する別の方法があるか、公匏ペヌゞから゜ヌスコヌドをダりンロヌドしおjavascriptsフォルダヌに貌り付けるこずができたす。

Railsアプリケヌションを開発しおいる堎合は、gemのむンストヌルがいかに簡単かを知っおいたす Gemfileぞのreact-rails远加
  gem 'react-rails', '~> 1.0' 

次に、レヌルに新しいgemをむンストヌルするように芪切に䌝えたす
 bundle install 

React-railsには、 Reactコンポヌネントが存圚するapp/assets/javascriptsフォルダヌ内にcomponents.jsファむルを䜜成するスクリプトがむンストヌルされおいたす。
 rails g react:install 

むンストヌルを開始した埌にapplication.jsファむルを芋るず、3぀の新しい行が衚瀺されたす。
 //= require react //= require react_ujs //= require components 

基本的に、これにはReactラむブラリが含たれ、コンポヌネントおよび類䌌のファむルはujs保存されujsファむル名から掚枬できるように、 react-railsはReactコンポヌネントのむンストヌルに圹立ち、Turbolinksむベントも凊理する控えめなJSドラむバヌが含たれおいたす。

リ゜ヌス䜜成



Recordリ゜ヌスを䜜成したす。これは、タむトルタむトルの日付日付ず金額金額で構成されたす。
scaffold生成を䜿甚する代わりに、 resourceゞェネレヌタを䜿甚したす。
scaffoldゞェネレヌタを䜿甚しお䜜成されたすべおのファむルずメ゜ッドを䜿甚するわけではありたせん。 そうしないず、scaffoldを起動しお未䜿甚のファむル/メ゜ッドを削陀するこずが可胜になりたすが、この堎合のプロゞェクトは少し汚いでしょう。 その埌、プロゞェクト内で次のコマンドを実行したす。
 rails g resource Record title date:date amount:float 

この魔法の埌、新しいモデルモデルコントロヌラヌコントロヌラヌずルヌトルヌトができたした。 次に、デヌタベヌスを䜜成し、移行を実行したす。
 rake db:create db:migrate 

さらに、次の方法でいく぀かのレコヌドを䜜成できたす。
 rails console Record.create title: 'Record 1', date: Date.today, amount: 500 Record.create title: 'Record 2', date: Date.today, amount: -100 

サヌバヌを起動するこずを忘れないでください
 rails s 

できた コヌドを曞くこずができたす。

ネストされたコンポヌネントレコヌドリスト



最初のタスクでは、䜜成したレコヌドをテヌブル内にレンダリングする必芁がありたす。
最初に、 RecordsController内にindexアクションを䜜成する必芁がありたす。
 # app/controllers/records_controller.rb class RecordsController < ApplicationController def index @records = Record.all end end 

ここで、 apps/views/records/に新しいindex.html.erbファむルを䜜成する必芁がありたす。このファむルは、RailsアプリケヌションずReactコンポヌネント間のブリッゞになりたす。 このタスクを実行するには、ヘルパヌメ゜ッドreact_componentを䜿甚したす。このメ゜ッドは、Reactずいう名前を取埗したす。これは、枡すデヌタず共にレンダリングするコンポヌネントです。
 <%# app/views/records/index.html.erb %> <%= react_component 'Records', { data: @records } %> 

このヘルパヌはreact-rails gemによっお提䟛されるこずに泚意しおください。別の統合Reactメ゜ッドを䜿甚するこずにした堎合、このヘルパヌは䜿甚できたせん。

これで、 localhost:3000/recordsアクセスできたす。 明らかに、䜕かが正しく機胜しおいたせん。これはすべお、レコヌドReactコンポヌネントが欠萜しおいるためです。 しかし、生成されたHTMLをブラりザヌ内に取り蟌むず、このようなものを挿入できたす。
 <div data-react-class="Records" data-react-props="{...}"> </div> 

このマヌクアップにより、 react_ujsはReactコンポヌネントをレンダリングしようずしおいるかどうかを刀断し、 react_ujsを介しお送信する蚭定を含むむンスタンスを䜜成したす。この堎合、コンテンツは@records

最初のコンポヌネントを䜜成し、 javascripts/componentsディレクトリ内に新しいファむルrecords.js.coffee䜜成したす。このファむルにはRecordsコンポヌネントが含たれたす。
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass render: -> React.DOM.div className: 'records' React.DOM.h2 className: 'title' 'Records' 

各コンポヌネントには、コンポヌネントのレンダリングを倉曎するrenderメ゜ッドが必芁ですReactComponentメ゜ッドは、 ReactComponentクラスのむンスタンスを返す必芁がありたす。そのため、Reactが再レンダリングを実装するず、最適に実行されたす。

発蚀。 別のケヌスでは、メ゜ッドのレンダヌ内のReactComponentsむンスタンスは、JSX構文を䜿甚しお蚘述できたす。
䞊蚘のコヌドず同等
  render: -> `<div className="records"> <h2 className="title"> Records </h2> </div>` 

個人的には、CoffeeScriptを䜿甚する堎合、コヌドはHAMLのように階局構造に倉換されるため、 React.DOM構文を䜿甚するこずを奜みたす。既存のERBコヌドをJSXに倉換したす。

ブラりザを曎新

画像

玠晎らしい。 最初のReactコンポヌネントをレンダリングしたした。 次に、メモを衚瀺したす。

さらに、Reactコンポヌネントのrenderメ゜ッドは、再レンダリングが必芁かどうかを理解するために、蚭定を䜿甚しお他のコンポヌネントや状態ず亀換するこずに䟝存しおいたす。 コンポヌネントの状態ずプロパティを必芁な倀で初期化する必芁がありたす。
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass getInitialState: -> records: @props.data getDefaultProps: -> records: [] render: -> ... 

getDefaultPropsメ゜ッドは、デヌタの転送を忘れた堎合、むンスタンス化するずきにコンポヌネントの蚭定を初期化し、 getInitialStateメ゜ッドはコンポヌネントの初期状態を生成したす。 通垞、Railsビュヌを䜿甚しおレコヌドを衚瀺する必芁がありたす。

行数をフォヌマットするためのヘルパヌメ゜ッドが必芁なようで、行の簡単なフォヌマットを挿入しお、すべおのcoffeeファむルで䜿甚できるようにしたすutils.js.coffee次の内容の新しいutils.js.coffeeファむルを䜜成したす。
 # app/assets/javascripts/utils.js.coffee @amountFormat = (amount) -> '$ ' + Number(amount).toLocaleString() 

新しいRecordコンポヌネントを䜜成し、個々のレコヌドを衚瀺し、 javascripts/componentsディレクトリに新しいrecord.js.coffeeファむルを䜜成しお、次のコヌドを貌り付ける必芁がありたす。
 # app/assets/javascripts/components/record.js.coffee @Record = React.createClass render: -> React.DOM.tr null, React.DOM.td null, @props.record.date React.DOM.td null, @props.record.title React.DOM.td null, amountFormat(@props.record.amount) 

Recordコンポヌネントは、レコヌドの各属性のセルを含むテヌブルの列に衚瀺されたす。 React.DOM.*これらのReact.DOM.*をカりントする心配はありたせんReact.DOM.*呌び出し、぀たり、コンポヌネントに属性を枡さないこずを意味したすReact.DOM.* 、次のコヌドでコンポヌネントのレコヌド内のrenderメ゜ッドを曎新したす。
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass ... render: -> React.DOM.div className: 'records' React.DOM.h2 className: 'title' 'Records' React.DOM.table className: 'table table-bordered' React.DOM.thead null, React.DOM.tr null, React.DOM.th null, 'Date' React.DOM.th null, 'Title' React.DOM.th null, 'Amount' React.DOM.tbody null, for record in @state.records React.createElement Record, key: record.id, record: record 

䜕が起こったのか芋たしたか 内郚にヘッダヌず本文を含むテヌブルを䜜成したした。 既存の各レコヌドに察しおRecord芁玠を䜜成したした。 蚀い換えるず、ビルトむン/カスタムReactコンポヌネント、Coolをネストしおいたす。 そう

動的な盞続人この堎合はレコヌドがある堎合、芁玠を動的に生成するための構成キヌを提䟛する必芁がありたす。したがっお、ReactがUIナヌザヌむンタヌフェむスを曎新する時間はあたりありたせん。
キヌRecord芁玠を䜜成するずきに、実際のレコヌドず䞀緒にrecord.id 。 これを行わない堎合、ブラりザヌのJSコン゜ヌルで譊告を取埗する必芁がありたすおそらく近い将来、頭痛の皮になるこずもありたす。

画像

ここでこのセクションのコヌドを芋るか、セクションの倉曎を芋るこずができたす 。

芪ず子の関係レコヌドの䜜成



䜜成されたすべおのレコヌドを衚瀺し、新しいレコヌドを䜜成するフォヌムを含めるこずもできたす。 この機胜をReact / Railsアプリケヌションに远加したしょう。 たず、コントロヌラヌのcreate methodを远加する必芁がcreate methodたす _strongparams䜿甚を忘れないでください
 class RecordsController < ApplicationController ... def create @record = Record.new(record_params) if @record.save render json: @record else render json: @record.errors, status: :unprocessable_entity end end private def record_params params.require(:record).permit(:title, :amount, :date) end end 

次に、Reactコンポヌネントを䜜成し、新しいレコヌドの䜜成を远跡する必芁がありたす。 コンポヌネントには、タむトルの日付ず金額を保存する独自の状態がありたす。
 # app/assets/javascripts/components/record_form.js.coffee @RecordForm = React.createClass getInitialState: -> title: '' date: '' amount: '' render: -> React.DOM.form className: 'form-inline' React.DOM.div className: 'form-group' React.DOM.input type: 'text' className: 'form-control' placeholder: 'Date' name: 'date' value: @state.date onChange: @handleChange React.DOM.div className: 'form-group' React.DOM.input type: 'text' className: 'form-control' placeholder: 'Title' name: 'title' value: @state.title onChange: @handleChange React.DOM.div className: 'form-group' React.DOM.input type: 'number' className: 'form-control' placeholder: 'Amount' name: 'amount' value: @state.amount onChange: @handleChange React.DOM.button type: 'submit' className: 'btn btn-primary' disabled: !@valid() 'Create record' 

創造的なものではなく、むンラむンブヌトストラップフォヌムです。 入力倀を蚭定しお属性の倀を決定する方法に泚意しおくださいonChange属性は、キヌが抌されるたびに呌び出されるメ゜ッドをアタッチしお凊理したす。handleChange handleChangeメ゜ッドは属性名を䜿甚し、入力によりむベントがトリガヌされ、倀の状態が曎新されたす。
# app/assets/javascripts/components/record_form.js.coffee

@RecordForm = React.createClass
...
handleChange: (e) ->
name = e.target.name
@setState "#{ name }": e.target.value

名前がtitleず䞀臎する堎合、文字列むンタヌプリタヌを䜿甚しお、 @setState title: e.target.valueに盞圓するキヌ@setState title: e.target.valueを動的に決定したす。 しかし、なぜ@setStateを䜿甚する@setStateでしょうか 通垞のJSオブゞェクトで通垞行うように、目的の<co倀をstateに蚭定できないのはなぜですか @setStateは2぀のアクションを実行する必芁があるため、これは次のずおりです。
  1. ステヌタスコンポヌネントの曎新
  2. 新しい状態に基づいおUIチェック/曎新を蚈画する

コンポヌネント内で状態を䜿甚するたびに、この情報をメモリに保持するこずが非垞に重芁です。 renderメ゜ッドの最埌にある送信ボタンを芋おみたしょう
 # app/assets/javascripts/components/record_form.js.coffee @RecordForm = React.createClass ... render: -> ... React.DOM.form ... React.DOM.button type: 'submit' className: 'btn btn-primary' disabled: !@valid() 'Create record' 

倀!@valid()ず共にdisabled属性を定矩したした。これは、ナヌザヌが提䟛したデヌタが正しいかどうかを評䟡するための有効なメ゜ッドを実装するこずを意味したす。
 # app/assets/javascripts/components/record_form.js.coffee @RecordForm = React.createClass ... valid: -> @state.title && @state.date && @state.amount 

簡単にするために、空の行で@state属性を再床怜蚌するだけです。 したがっお、状態が曎新を受信するたびに、[ Create recordオン/オフのCreate record ]ボタンはデヌタの怜蚌に䟝存したす。

画像

これで、コントロヌラヌずフォヌムが配眮されたした。 新しいレコヌドをサヌバヌに送信したす。 むベントプレれンテヌションフォヌムを凊理する必芁がありたす。 タスクを完了するには、フォヌムの属性をonSubmitず新しいhandleSubmitメ゜ッドに远加する必芁がありたす onChangeむベントでも同じこずを行いonChangeた。
 # app/assets/javascripts/components/record_form.js.coffee @RecordForm = React.createClass ... handleSubmit: (e) -> e.preventDefault() $.post '', { record: @state }, (data) => @props.handleNewRecord data @setState @getInitialState() , 'JSON' render: -> React.DOM.form className: 'form-inline' onSubmit: @handleSubmit ... 

行ごずに新しいメ゜ッドを確認したしょう。
  1. フォヌムを送信しない
  2. 珟圚のURLの新しいレコヌド情報をPOST
  3. 成功したコヌルバック


成功したコヌルバックは、このプロセスの鍵です。新しいレコヌドの䜜成が成功した埌、誰かがこのアクションを報告する必芁があり、ステヌタスが新しい倀に曎新されたす。 このコンポヌネントが蚭定たたは@props を介しお他のコンポヌネントずやり取りするこずに぀いお蚀及したずきのこずを芚えおいたすか だから、そうです。 珟圚のコンポヌネントは、 @props.handleNewRecordを介しお芪コンポヌネントに情報を送り返し、新しいレコヌドが䜜成されたこずを知らせたす。

ごRecordForm 、 RecordForm芁玠を䜜成するずきは、 React.createElement RecordForm 、 handleNewRecord: @addRecordなどのメ゜ッドぞの参照をhandleNewRecord蚭定を枡す必芁がありたす。 さお、芪レコヌドコンポヌネントは「すべおの堎所」にあり、既存のすべおのレコヌドの状態があるため、新しく䜜成したレコヌドでこの状態を曎新する必芁がありたす
addRecord内に新しいaddRecordメ゜ッドを远加し、h2タむトルの盎埌renderメ゜ッド内に新しいRecordForm芁玠を䜜成したす。
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass ... addRecord: (record) -> records = @state.records.slice() records.push record @setState records: records render: -> React.DOM.div className: 'records' React.DOM.h2 className: 'title' 'Records' React.createElement RecordForm, handleNewRecord: @addRecord React.DOM.hr null 

ブラりザを曎新し、フォヌムに新しいレコヌドを入力し、[レコヌドのCreate record ]をクリックしおも驚くこずでCreate recordたせん。今回は、すぐにレコヌドが远加され、クリック埌にフォヌムが空になりたした。 曎新が完了したした。もちろん、バック゚ンドは新しいデヌタでいっぱいになりたした。
画像

Reactず䞀緒に別のJSフレヌムワヌクたずえばhangar を䜿甚しお同様の機胜を䜜成する堎合、POSTリク゚ストにRailsが必芁ずするCSRFトヌクンが含たれおいないため、問題が発生する可胜性がありたす。 jqueryを䜿甚しおバック゚ンドずやり取りするため、 Rails jquery_ujs控えめなドラむバヌは、各AJAXリク゚ストにCSRFトヌクンを含めたす。 かっこいい。

このセクションでコヌドの結果を確認するか、 ここで倉曎を確認できたす。

コンポヌネントの再利甚



䞀郚の良いメトリックがなければ、アプリは䜕を望みたすか りィンドりの䞊郚にいく぀かの情報を䜿甚したボックスを远加したしょう。 ボックス3では、クレゞットの合蚈数、デビットの合蚈数、残高の倀を瀺したす。
3぀のコンポヌネントで䜜業しおいるように芋えたすか、それずも蚭定の1぀だけですか

テキストの量ずタむプの蚭定を受け取る新しいAmountBoxコンポヌネントを䜜成できたす。 新しいファむルを䜜成するず、 javascripts/components/からamount_box.js.coffeeが呌び出され、次のコヌドが挿入されたす。
 # app/assets/javascripts/components/amount_box.js.coffee @AmountBox = React.createClass render: -> React.DOM.div className: 'col-md-4' React.DOM.div className: "panel panel-#{ @props.type }" React.DOM.div className: 'panel-heading' @props.text React.DOM.div className: 'panel-body' amountFormat(@props.amount) 

ブヌトストラップパネルを䜿甚するだけで、芁玠は「ブロック」メ゜ッドで情報を衚瀺し、蚭定の皮類によっお色を蚭定したす。
たた、蚭定の数を読み取り、通貚圢匏で衚瀺するamountFormatず呌ばれる、非垞に簡単な圢匏のメ゜ッドが含たれおいたす。

泚文には完党な゜リュヌションがありたす。 衚瀺するデヌタに応じお必芁な蚭定を枡すには、メむン芁玠内でこの芁玠を3回䜜成する必芁がありたす。 メ゜ッドの蚈算機を䜜成したしょう。 最初に、 Recordコンポヌネントを開き、次のメ゜ッドを远加したす。
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass ... credits: -> credits = @state.records.filter (val) -> val.amount >= 0 credits.reduce ((prev, curr) -> prev + parseFloat(curr.amount) ), 0 debits: -> debits = @state.records.filter (val) -> val.amount < 0 debits.reduce ((prev, curr) -> prev + parseFloat(curr.amount) ), 0 balance: -> @debits() + @credits() ... 

倀が0より倧きいすべおのレコヌドの貞方の合蚈。金額が0より小さいすべおのレコヌドの借方ず残高倀の合蚈。 これで、適切な堎所に蚈算可胜なメ゜ッドができたした。 内郚にAmountBox芁玠を䜜成し、メ゜ッド RecordFormコンポヌネントのすぐ䞊をレンダリングするだけです。
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass ... render: -> React.DOM.div className: 'records' React.DOM.h2 className: 'title' 'Records' React.DOM.div className: 'row' React.createElement AmountBox, type: 'success', amount: @credits(), text: 'Credit' React.createElement AmountBox, type: 'danger', amount: @debits(), text: 'Debit' React.createElement AmountBox, type: 'info', amount: @balance(), text: 'Balance' React.createElement RecordForm, handleNewRecord: @addRecord ... 

この機胜はこれで完了です ブラりザを曎新したす。 前に蚈算した3぀のボックスが衚瀺されおいるはずです。 しかし、埅っおください もっずありたす 新しいレコヌドを䜜成しお、䜜品の魔法をご芧ください。

画像

コヌドの結果を芋るこずができたす。
ここで修正

setState / replaceStateレコヌドを削陀したす



リストの次の機胜は、レコヌドの削陀です。 レコヌドテヌブルに新しいアクション列が必芁です。 この列には、゚ントリごずに削陀ボタンがあり、UIの暙準です。 前の䟋のように、Railsコントロヌラでメ゜ッドを䜜成および削陀する必芁がありたす。
 # app/controllers/records_controller.rb class RecordsController < ApplicationController ... def destroy @record = Record.find(params[:id]) @record.destroy head :no_content end ... end 

これは、この機胜に必芁なすべおのサヌバヌ偎コヌドです。 次に、 Records Reactコンポヌネントを開き、アクションのテヌブルヘッダヌの右偎に列を远加したす。
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass ... render: -> ... # almost at the bottom of the render method React.DOM.table React.DOM.thead null, React.DOM.tr null, React.DOM.th null, 'Date' React.DOM.th null, 'Title' React.DOM.th null, 'Amount' React.DOM.th null, 'Actions' React.DOM.tbody null, for record in @state.records React.createElement Record, key: record.id, record: record 

最埌に、レコヌドコンポヌネントを開き、[削陀]リンクを含む列を远加したす
 # app/assets/javascripts/components/record.js.coffee @Record = React.createClass render: -> React.DOM.tr null, React.DOM.td null, @props.record.date React.DOM.td null, @props.record.title React.DOM.td null, amountFormat(@props.record.amount) React.DOM.td null, React.DOM.a className: 'btn btn-danger' 'Delete' 

ファむルを保存し、ブラりザを曎新するず、むベントが添付されおいないボタンが機胜しなくなりたす。

画像

いく぀かの機胜を远加したしょう。 リストを䜿甚しおRecordFormコンポヌネントから孊んだように
  1. Recordコンポヌネントの子孫内のむベントを削陀したすonClick
  2. アクションを実行したすこの堎合、サヌバヌにDELETEリク゚ストを送信したす
  3. このアクションの芪コンポヌネントのレコヌドに通知する蚭定によるハンドラヌメ゜ッドの送受信
  4. レコヌドコンポヌネントの状態を曎新する


最初のステップを実装するために、同じ方法でOnClickハンドラヌをRecordに远加できOnClick onSubmitハンドラヌをonSubmitにRecordFormしお、新しいレコヌドを䜜成したす。 幞いなこずに、Reactはほずんどの䞀般的なブラりザヌむベントを通垞の圢匏で実装しおいたす。 したがっお、ブラりザ間の互換性に぀いお心配する必芁はありたせんむベントの完党なリストはこちらで確認できたす。

蚘録コンポヌネントを再床開き、次のように「 handleDeleteな」削陀ボタンに新しいhandleDeleteメ゜ッドずOnClick属性を远加したす。
 # app/assets/javascripts/components/record.js.coffee @Record = React.createClass handleDelete: (e) -> e.preventDefault() # yeah... jQuery doesn't have a $.delete shortcut method $.ajax method: 'DELETE' url: "/records/#{ @props.record.id }" dataType: 'JSON' success: () => @props.handleDeleteRecord @props.record render: -> React.DOM.tr null, React.DOM.td null, @props.record.date React.DOM.td null, @props.record.title React.DOM.td null, amountFormat(@props.record.amount) React.DOM.td null, React.DOM.a className: 'btn btn-danger' onClick: @handleDelete 'Delete' 

削陀ボタンをクリックhandleDeleteはAJAXリク゚ストをサヌバヌに送信したす
バック゚ンドでレコヌドを削陀し、その埌、 handleDeleteRecordを介しおこのアクションに぀いお芪コンポヌネントに通知したす。蚭定でハンドラヌを䜿甚できるため、芪コンポヌネントでのRecord芁玠の䜜成を芏制する必芁がありたす。
远加のhandleDeleteRecordプロパティを有効にし、祖先に実際のハンドラメ゜ッドを実装するには
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass ... deleteRecord: (record) -> records = @state.records.slice() index = records.indexOf record records.splice index, 1 @replaceState records: records render: -> ... # almost at the bottom of the render method React.DOM.table React.DOM.thead null, React.DOM.tr null, React.DOM.th null, 'Date' React.DOM.th null, 'Title' React.DOM.th null, 'Amount' React.DOM.th null, 'Actions' React.DOM.tbody null, for record in @state.records React.createElement Record, key: record.id, record: record, handleDeleteRecord: @deleteRecord 

基本的に、 deleteRecordメ゜ッドは、レコヌドの状態の珟圚のコンポヌネントをコピヌし、削陀する必芁があるレコヌドむンデックスで怜玢を実行したす。 かわいい暙準のjs操䜜。

状態ずやり取りする新しい方法を導入したしたが、replaceState䞻な違いはsetState、replaceState1぀目はオブゞェクトの1぀の状態キヌのみを曎新し、2぀目は送信する新しいオブゞェクトでコンポヌネントの珟圚の状態を完党に再定矩するこずです。

コヌドの最埌のビットを曎新した埌、ブラりザりィンドりを曎新しお゚ントリを削陀しようずするず、次の2぀のこずが起こりたす。
  1. レコヌドがテヌブルから消えたす
  2. むンディケヌタヌはすぐに番号を曎新する必芁がありたすこれに他のコヌドは必芁ありたせん。


画像

ほが完了したしたが、最埌の機胜をむンストヌルする前に、少しのリファクタリングを同時に適甚しお、新しいReact関数を導入できたす。

リファクタリング状態ヘルパヌ



最埌の機胜。テヌブルのEdit各Deleteボタンの埌に远加のボタンを远加したす。ボタンをクリックするEditず、ナヌザヌがレコヌドの内容を曎新できるむンラむンフォヌムを開いお、行党䜓ず読み取り専甚状態を線集状態に切り替えたす。曎新されたコンテンツを送信するか、行に察するアクションをキャンセルするず、レコヌドは元の読み取り専甚状態に戻りたす。

前の章から掚枬したように、コンポヌネント内のレコヌドの各状態を切り替えるために、いく぀かのデヌタを凊理する必芁がありたすRecord。これは、Reactがリアクティブデヌタストリヌムず呌ぶものを䜿甚する堎合です。
線集フラグずhandleToggleメ゜ッドをrecord.js.coffeeに远加したしょう

 # app/assets/javascripts/components/record.js.coffee @Record = React.createClass getInitialState: -> edit: false handleToggle: (e) -> e.preventDefault() @setState edit: !@state.edit ... 


線集フラグはデフォルトでオフになりhandleToggle、線集をfalseからtrueに倉曎したす。その逆も同様です。handleToggleナヌザヌでOnClickむベントをトリガヌするだけです。

次に、read / read_and_edit行の2぀のバヌゞョンを制埡し、線集に応じお条件付きで衚瀺する必芁がありたす。幞いなこずに、芖芚化メ゜ッドがReact芁玠を返す限り、任意のアクションを自由に実行できたす。我々は
いく぀かのヘルパヌメ゜ッドを定矩するこずができたすrecordRowし、recordFormそしお内容に応じお、可芖化に条件付きでそれらを呌び出したす@ state.edit。

すでに最初のオプションがありrecordRow、これが珟圚のレンダリング方法です。レンダリングコンテンツを新しいメ゜ッドに移動したしょうrecordRow 远加のコヌドを远加したす
 # app/assets/javascripts/components/record.js.coffee @Record = React.createClass ... recordRow: -> React.DOM.tr null, React.DOM.td null, @props.record.date React.DOM.td null, @props.record.title React.DOM.td null, amountFormat(@props.record.amount) React.DOM.td null, React.DOM.a className: 'btn btn-default' onClick: @handleToggle 'Edit' React.DOM.a className: 'btn btn-danger' onClick: @handleDelete 'Delete' ... 

䜙分に远加したしたReact.DOM。芁玠はからのシグナルを埅っonClickおいたすhandleToggle

先に進みたす。実装recordFormは次の構造にする必芁がありたすが、各セルに入力フィヌルドがありたす。ref入力に新しい属性を䜿甚し、利甚可胜にしたす。このコンポヌネントは状態を凊理しないため、この新しい属性により、コンポヌネントはナヌザヌから提䟛されたデヌタを読み取るこずができたす。@refs:

 # app/assets/javascripts/components/record.js.coffee @Record = React.createClass ... recordForm: -> React.DOM.tr null, React.DOM.td null, React.DOM.input className: 'form-control' type: 'text' defaultValue: @props.record.date ref: 'date' React.DOM.td null, React.DOM.input className: 'form-control' type: 'text' defaultValue: @props.record.title ref: 'title' React.DOM.td null, React.DOM.input className: 'form-control' type: 'number' defaultValue: @props.record.amount ref: 'amount' React.DOM.td null, React.DOM.a className: 'btn btn-default' onClick: @handleEdit 'Update' React.DOM.a className: 'btn btn-danger' onClick: @handleToggle 'Cancel' ... 

心配しないで。このメ゜ッドはもっず倧きくおもかたいたせんが、単なるHTML構文です。
発蚀。@handleEditナヌザヌがボタンをクリックしたずきに呌び出し、Updateレコヌドを削陀する1぀の実装ずしお同様のスレッドを䜿甚したす。

それらの䜜成方法の違いに気づきたしたReact.DOM.inputsかdefaultValue初期入力を蚭定する代わりにデフォルトを䜿甚したす。これは、倀なしでのみ䜿甚OnChange
するず最終的に読み取り専甚入力ずしお䜜成されるためです。

最埌に、芖芚化メ゜ッドは次のコヌドに芁玄されたす。

 # app/assets/javascripts/components/record.js.coffee @Record = React.createClass ... render: -> if @state.edit @recordForm() else @recordRow() 

, , , .

画像

, Rails:
 # app/controllers/records_controller.rb class RecordsController < ApplicationController ... def update @record = Record.find(params[:id]) if @record.update(record_params) render json: @record else render json: @record.errors, status: :unprocessable_entity end end ... end 

, handleEdit , AJAX , , handleEditRecord , @props , , :
 # app/assets/javascripts/components/record.js.coffee @Record = React.createClass ... handleEdit: (e) -> e.preventDefault() data = title: React.findDOMNode(@refs.title).value date: React.findDOMNode(@refs.date).value amount: React.findDOMNode(@refs.amount).value # jQuery doesn't have a $.put shortcut method either $.ajax method: 'PUT' url: "/records/#{ @props.record.id }" dataType: 'JSON' data: record: data success: (data) => @setState edit: false 

簡単にするために、ナヌザヌデヌタをチェックせず、React.findDOMNode@ refs.fieldName.valueを介しおそれらを読み取り、バック゚ンドにそのたた送信したす。成功のために状態を曎新しお線集モヌドに切り替えるこずはオプションですが、ナヌザヌは確かにそのこずに感謝したす。

最埌に重芁なこずですが、レコヌドコンポヌネントの状態を曎新しお、前のレコヌドを新しいバヌゞョンのレコヌドの子孫で䞊曞きし、Reactに魔法をかける必芁がありたす。実装は次のようになりたす。
 # app/assets/javascripts/components/records.js.coffee @Records = React.createClass ... updateRecord: (record, data) -> index = @state.records.indexOf record records = React.addons.update(@state.records, { $splice: [[index, 1, data]] }) @replaceState records: records ... render: -> ... # almost at the bottom of the render method React.DOM.table React.DOM.thead null, React.DOM.tr null, React.DOM.th null, 'Date' React.DOM.th null, 'Title' React.DOM.th null, 'Amount' React.DOM.th null, 'Actions' React.DOM.tbody null, for record in @state.records React.createElement Record, key: record.id, record: record, handleDeleteRecord: @deleteRecord, handleEditRecord: @updateRecord 

前のセクションで孊んだReact.addons.updateように、状態の倉曎を䜿甚するず、より具䜓的な方法に぀ながる可胜性がありたす。レコヌドずレコヌド間の最埌のリンクは@updateRecord、handleEditRecord蚭定を介しお枡されるメ゜ッドです。

ブラりザを最埌に曎新しお、既存の゚ントリを曎新しおみおください。ペヌゞ䞊郚のボックスが、倉曎したすべおの゚ントリを远跡する方法に泚意しおください。
画像

できたした
小さなRails + Reactアプリケヌションをれロから䜜成したした

コヌドの結果はこちらで確認できたすが、新しい倉曎はこちらです。

最終的な考えReact.js、シンプルさず柔軟性



Reactの機胜のいく぀かを芋お、新しい抂念を導入するこずはほずんどないこずを孊びたした。 XたたはYフレヌムを蚀う人々のコメントを聞きたした。JavaScriptは、新しく導入されたすべおの抂念のために急な孊習曲線を持っおいたすが、これはReactのケヌスではありたせん。むベントハンドラヌやバむンディングなどの基本的なJavaScriptの抂念を実装し、孊習ず理解を容易にしたす。繰り返しになりたすが、その長所の1぀はそのシンプルさです。

たた、䟋を通しお、「アクティブな䜜業」ず「CoffeeScript、JQuery、Turbolinks、およびその他のレヌルずの連携」レヌルオヌケストラに統合する方法を孊びたした。しかし、これが望たしい結果を達成する唯䞀の方法ではありたせん。たずえば、Turbolinksを䜿甚しない堎合react_ujsは䞍芁、react-reils gemの代わりにRailsアセットを䜿甚できたす。JBuilderを䜿甚しお、JSONオブゞェクトをレンダリングする代わりに、より耇雑なJSON応答を䜜成できたす。ただし、同じ玠晎らしい結果を埗るこずができたす。

Source: https://habr.com/ru/post/J281735/


All Articles