Tìm hiểu về ReactJS với Rails
Bài đăng này đã không được cập nhật trong 8 năm
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
All rights reserved