さらにテキストでは、斜体で示されているすべてのもの、私のコメント(多くはありません)
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応答を作成できます。ただし、同じ素晴らしい結果を得ることができます。