Tìm hiểu về ReactJS với Rails
Trong một khoảng thời gian tìm hiểu về ReactJS, hôm nay mình viết một bài viết về chủ đề này. Để tìm hiểu về React là gì? v.v.. thì có rất nhiều bài viết trên blog này rồi, do vậy mình đi thẳng vào áp dụng với Rails. Tiếp xúc với Rails chắc chúng ta quen thuộc với scaffold để sinh tự động với ...
Trong một khoảng thời gian tìm hiểu về ReactJS, hôm nay mình viết một bài viết về chủ đề này. Để tìm hiểu về React là gì? v.v.. thì có rất nhiều bài viết trên blog này rồi, do vậy mình đi thẳng vào áp dụng với Rails.
Tiếp xúc với Rails chắc chúng ta quen thuộc với scaffold để sinh tự động với nhóm chức năng crud.
Bài viết này mình sẽ viết về thực thi nhóm chức năng này sử dụng React trong framework Rails.
Để tiện theo dõi mình đặt tên app là demo-react. App này chỉ có chức năng crud với resource là records.
$ rails new demo-react $ cd demo-react $ rails g scaffold records title:string content:text $ rake db:create $ rake db:migrate
Sơ qua về React
Hiểu một cách đơn gianr, ngắn gọn về react.js như tên gọi của nó đó là một framework về javascript.
React.js mục đích để tạo ra cấu trúc DOM ảo qua các định nghĩa trong các tệp tin javascript.
Render()
ReactJS sử dụng phương thức render để tạo ra cấu trúc DOM ảo trên một vị trí bất kỳ trên DOM thật.
$ -> ReactDOM.render( React.DOM.div({}, "Hello world!"), document.getElementById("start") )
Lệnh phía trên sẽ tạo ra một thẻ <div>Hello world!</div> bên trong định danh #start trên DOM thật.
Mình cũng có thể định nghĩa thêm các class hay id cho thẻ trên bằng cách khai báo vào bên trong {} cặp ngoặc này.
Tổng quan lại cú pháp cho phương thức render là
ReactDOM.render(what, where)
Ở phần what chúng ta có thể tạo ra bất cứ thứ gì mình muốn với cú pháp tổng quan là
React.DOM.*
* ở đây có thể là thẻ div, a, h2, v.v..
Components
Việc viết các components cho các chức năng mình cần để tiện quan sát code, dễ đọc và sử dụng ở những nơi mà mình muốn một cách dễ dàng và hiệu qủa hơn.
Ví dụ về tạo một component
my_component = React.createClass function_name: -> # code here render: -> # code here
Sử dụng component
$ -> element = React.createElement(my_component) ReactDOM.render( element, document.getElementById("start") )
state
Mỗi một component đều có 1 state. Dùng để quản lý các trạng thái của component.
Các phương thức với state như:
# Thiết lập gía trị khởi tạo ban đầu getInitialState() # Thiết lập gía trị mới cho state setState() # Gán thay đổi gía trị trong state replaceState()
Việc thay đổi state sẽ được tự động áp dụng cho render của component.
Lấy ví dụ đơn gianr khi mình tạo mới 1 record, sau khi dùng phương thức replaceState() thì record mới đó sẽ được render ra DOM mà không cần load lại trang.
Props
Props là Properties mà chúng ta đã đưa vào component từ phương thức render.
Các thao tác với object của form, v.v.. đều sử dụng props.
Một số hàm với props
# Khởi tạo một gía trị ban đầu cho props trong component my_component = React.createClass ... getDefaultProps: -> object: [] render: -> # code here
crud trong demo rails app
Phần trên mình đã đi vào gioi thiệu khái quát một số phần cơ bản, quan trọng về reactjs. Tới phần này mình sẽ đi vào triển khai nhóm chức năng crud.
Để bắt đầu với Reactjs tới thực hiện chức năng như trên mình cần làm từng bước từ việc cài đặt tới viết mã.
Cài đặt ReactJS trong rails app
Sử dụng Gem. Copy dòng sau vào Gemfile
gem 'react-rails', '~> 1.0'
Chạy bundle install để cài đặt gem trên.
Chạy lệnh sau để require cần thiết cho app của mình.
rails g react:install
Bản chất của lệnh trên là tạo ra thư mục components trong javascripts và 3 dòng sau vào application.js
//= require react //= require react_ujs //= require components
Để sử dụng các addons của thư viện, copy dòng sau vào config/application.rb
config.react.addons = true
Để debug với react trong development.rb
config.react.variant = :development
Liệt kê toàn bộ records
Trong controller records như sau:
# app/controllers/records_controller.rb class RecordsController < ApplicationController def index @records = Record.all end end
Mình sẽ sử dụng phương thức react_component để render ra toàn bộ records như sau:
<%# app/views/records/index.html.erb %> <%= react_component 'Records', { data: @records } %>
Khi đó truy cập vào localhost:3000/records sẽ thấy như sau:
<div data-react-class="Records" data-react-props="{...}"> </div>
Để render ra các records thì cần viết phương thức render như sau: Tạo file javascripts/components/records.coffee với nội dung như sau:
# app/assets/javascripts/components/records.js.coffee @Records = React.createClass getInitialState: -> records: @props.data getDefaultProps: -> records: [] 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, 'title' React.DOM.th null, 'content' React.DOM.tbody null, for record in @state.records React.createElement Record, key: record.id, record: record
Một số lưu ý là:
Như mình đã nói ở phía đầu bài, các hàm getInitialState() và getDefaultProps() để khởi tạo gía trị ban đầu.
@Records đó chính là tên mà react_component đã render ra ở phía trên.
Hàm render trên sẽ tạo ra một thẻ div với class là records và thẻ tiêu đề h2 gồm chữ Records.
Như chúng ta thấy ở trên có hàm React.createElement Record. Đó chính là hàm render ra các record.
Để có được các record thì chúng ta cần viết những gì chúng ta cần render ra, và sẽ viết nó là một component tên là Record như sau:
# app/assets/javascripts/components/record.js.coffee @Record = React.createClass render: -> React.DOM.tr null, React.DOM.td null, @props.record.title React.DOM.td null, @props.record.content
Nếu là người đã từng làm với Rails chúng ta có thể hiểu một cách tương tự như sau:
File records.coffee định nghĩa tương tự records.slim
File record.coffee tương tự record.slim
Tạo mới một record
Để tạo mới một record đơn gianr chúng ta cần phải có 1 form để submit các thuộc tính mà mình đã điền vào lên server.
Việc này chúng ta làm hoàn toàn bằng js, bởi đây là reactjs. mình sẽ không tạo form tĩnh bằng html.
Để tạo form chúng ta làm như sau. Tạo file record_form.coffee trong mục javascripts/components/ như sau:
# app/assets/javascripts/components/record_form.js.coffee @RecordForm = React.createClass getInitialState: -> title: ' content: ' handleChange: (e) -> name = e.target.name @setState "#{ name }": e.target.value valid: -> @state.title && @state.content render: -> React.DOM.form className: 'form-inline' 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: 'text' className: 'form-control' placeholder: 'Content' name: 'content' value: @state.content onChange: @handleChange React.DOM.button type: 'submit' className: 'btn btn-primary' disabled: !@valid() 'Create record'
Như phía trên thì chúng ta có hàm khởi tạo gia' trị ban đầu cho form đều là rỗng. Hàm kiểm tra thay đổi các trường input và hàm kiểm tra đã điền hay chưa? valid.
Đến đây chúng ta đã có 1 form để điền dữ liệu và nút submit. Tuy nhiên chưa thể submit được dữ liệu lên server. Chúng ta cần có hàm xử lý button submit trên.
Tạo phương thức handleSubmit như sau:
# app/assets/javascripts/components/record_form.js.coffee @RecordForm = React.createClass ... handleSubmit: (e) -> e.preventDefault() data = JSON.stringify({record: @state}) $.ajax url: "/records" type: "POST" dataType: "JSON" contentType: "application/json" processData: false data: data success: (data) => @props.handleNewRecord data @setState @getInitialState() render: -> React.DOM.form className: 'form-inline' onSubmit: @handleSubmit ...
Hàm trên sẽ thực hiện POST dữ liệu lên server ở dạng JSON. Sau khi thành công thì phương thức setState sẽ set lại gia' trị cho form như ban đầu đồng thời gọi phương thức handleNewRecord
Như mình đã viết ở phần đầu, các phương thức thao tác với state để áp dụng cho phương thức render ra DOM của component. Do vậy sau khi submit data thành công, record đã được tạo ra thì cần hiển thị nó ngay sau đó trên DOM.
Để làm được việc này, chúng ta có phương thức là handleNewRecord, mình sẽ viết phương thức này như sau:
# 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 ...
handleNewRecord sẽ gọi phương thức addRecord phía trên.
Hàm addRecord sẽ thực hiện update thêm record đã tạo vào mảng records đã khởi tạo ban đầu bởi @state.records thêm một record mới tạo.
@setState records: records
Dòng trên sẽ thiết đặt gía trị mới cho records. Đó là gía trị sau khi đã thêm mới một record.
Chúng ta cũng có thể sử dụng component của react cho hàm addRecord như sau:
addRecord: (record) -> records = React.addons.update(@state.records, {$push: [record]}) @setState records: records
Như vậy chúng ta đã hoàn thành xong tính năng tạo mới một bản ghi với reactjs.
Tham khảo tính năng update, delete tại phần tham khảo.
Trên đây là một số kiến thức mình tìm hiểu được về ReactJs. Mình vẫn đang tiếp tục tìm hiểu về tính năng phân trang và kết hợp các associations trong các bản ghi.
Mong nhận được góp ý từ phía bạn đọc. Cảm ơn mọi người!
Tham khảo
- Cuốn Rails Meet React
- https://www.airpair.com/reactjs/posts/reactjs-a-guide-for-rails-developers