さらにテキストでは、斜体で示されているすべてのもの、私のコメント(多くはありません)
      React.jsの概要
React.jsはJavaScriptフレームワークチームの新しい人気者であり、そのシンプルさが際立っています。 他のフレームワークが完全なMVC (Model View Controller)アプローチを実装する場合、ビュー(ディスプレイ)(事実-一部の人々はこれらのフレームワークのディスプレイ(V)の一部をReactで書き換える)のみを実装するようにReactに指示できます。
Reactアプリケーションは、コンポーネントとステータスの2つの基本原則に基づいています。 コンポーネントは、組み込みまたはカスタムの小さなコンポーネントで構成できます。 Facebookのスタッフが一方向のリアクティブデータストリームを呼び出すことは、インターフェイス(UI)がすべての状態変化に対応することを意味します。
React.jsの優れた機能の1つは、追加の依存関係を必要としないことです。これにより、jsライブラリとの接続が保証されます。 これを使用して、外部インターフェイスを作成するためにRailsスタックに含めるか、「ステロイドのレール」を作成するように言うことができます。
アプリケーションコストトラッキングレイアウト
このガイドでは、小さなアプリケーションをゼロから作成して、アクションを追跡します。 各レコード( 以降、Recordと同じ )は、日付、名前、および金額で構成されます。 エントリは、金額がゼロより大きい場合はクレジットと見なされ、それ以外の場合はクレジットと見なされます。 プロジェクトのレイアウトは次のとおりです。
      合計すると、アプリケーションは次のように動作します。
- ユーザーが水平形式で新しいレコードを作成すると、レコードテーブルに挿入されます
 - ユーザーは既存の投稿を編集できます。
 - [削除]ボタンをクリックすると、テーブルから関連付けが削除されます。
 - 既存のレコードを追加、編集、または削除すると、ページ上部のボックスの量が更新されます
 
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つのアクションを実行する必要があるため、これは次のとおりです。
- ステータスコンポーネントの更新
 - 新しい状態に基づいて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 ...
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      行ごとに新しいメソッドを確認しましょう。
- フォームを送信しない
 - 現在のURLの新しいレコード情報をPOST
 - 成功したコールバック
 
成功したコールバックは、このプロセスの鍵です。新しいレコードの作成が成功した後、誰かがこのアクションを報告する必要があり、ステータスが新しい値に更新されます。 このコンポーネントが設定(または
@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
      
      コンポーネントから学んだように:
- Recordコンポーネントの子孫内のイベントを削除します(onClick)
 - アクションを実行します(この場合、サーバーにDELETEリクエストを送信します)
 - このアクションの親コンポーネントのレコードに通知する(設定によるハンドラーメソッドの送受信)
 - レコードコンポーネントの状態を更新する
 
最初のステップを実装するために、同じ方法で
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
      
      、
replaceState
      
      1つ目はオブジェクトの1つの状態キーのみを更新し、2つ目は送信する新しいオブジェクトでコンポーネントの現在の状態を完全に再定義することです。
コードの最後のビットを更新した後、ブラウザウィンドウを更新してエントリを削除しようとすると、次の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応答を作成できます。ただし、同じ素晴らしい結果を得ることができます。