12/08/2018, 10:16
ReactJS và Ruby on Rails
ReactJS là một Javascript Framework cực kỳ mạnh được tạo ra bởi Facebook. Nó đang là chủ để rất nóng trong thời gian gần đây. Vì vậy mình đã thử viết 1 ứng dụng với ReatcJS và cảm thấy nó khá hấp dẫn về tốc độ xử lý. Ví dụ dưới đây mình viết trên Ruby on Rails Để bắt đầu thì chung ta trước ...
-
ReactJS là một Javascript Framework cực kỳ mạnh được tạo ra bởi Facebook. Nó đang là chủ để rất nóng trong thời gian gần đây. Vì vậy mình đã thử viết 1 ứng dụng với ReatcJS và cảm thấy nó khá hấp dẫn về tốc độ xử lý. Ví dụ dưới đây mình viết trên Ruby on Rails
-
Để bắt đầu thì chung ta trước hết cài đặt môi trường làm việc với ReactJS
- Thêm react-rails tới gemfile của bạn :
gem 'react-rails', '~> 1.0' - Tiếp đó, bạn chạy cài đặt:
rails g react:install
- Nó sẽ tạo cho bạn 1 file components.js ở trong thư mục app/assets/javascripts/components/.
- Trong file application.js của bạn sẽ thêm :
//= require react //= require react_ujs //= require components - Tiếp đó bạn tạo 1 file model.
rails g model IngredientSuggestions item:string
- Tại thời điểm này, bạn có thể sử dụng lệnh
rake db:migrate - Tạo 1 controller có tên là **ingredient_suggestions_controller.rb**. Trong đó bạn viết: ```ruby class IngredientSuggestionsController < ApplicationController def index @ingredients = IngredientSuggestion.select("id, item").order("item ASC").to_json end def update ingredient = IngredientSuggestion.find(params[:id]) ingredient.item = params[:item] ingredient.save! render :nothing => true, :status => 200 end def destroy ingredient = IngredientSuggestion.find(params[:id]) ingredient.destroy render :nothing => true, :status => 200 end end 3. Dữ liệu Model trong Fluxxor - Ở đây chúng ta tạo 1 file có tên là **ingredient_suggestions.jsx**. Một đối tượng JavaScript lưu giữ dữ liệu và xác định các hành động mà của nó: ```javascript var fluxIngredientSuggestionsStore = {}; fluxIngredientSuggestionsStore.constants = { UPDATE_INGREDIENT: "UPDATE_INGREDIENT", DELETE_INGREDIENT: "DELETE_INGREDIENT", }; - Các đối tượng có chứa các dữ liệu của mình, khởi tạo thông qua Fluxxor createStore method. ```javascript fluxIngredientSuggestionsStore.store = Fluxxor.createStore({ initialize: function(options) { this.ingredients = options.ingredients || []; this.bindActions(fluxIngredientSuggestionsStore.constants.UPDATE_INGREDIENT, this.onUpdateIngredient, fluxIngredientSuggestionsStore.constants.DELETE_INGREDIENT, this.onDeleteIngredient); }, getState: function() { return { ingredients: this.ingredients, }; }, onUpdateIngredient: function(payload) { payload.ingredient.item = payload.new_name; this.emit("change") }, onDeleteIngredient: function(payload) { this.ingredients = this.ingredients.filter(function(ingredient) { return ingredient.id != payload.ingredient.id }); this.emit("change"); } }); - Các đối tượng cũng chứa các hành động của chúng, thông qua các API đơn giản: ```javascript fluxIngredientSuggestionsStore.actions = { updateIngredient: function(ingredient, new_name) { this.dispatch(fluxIngredientSuggestionsStore.constants.UPDATE_INGREDIENT, { ingredient: ingredient, new_name: new_name }); $.ajax({ type: "PUT", url: "/ingredient_suggestions/" + ingredient.id, data: { item: new_name }, success: function() { $.growl.notice({ title: "Ingredient suggestion updated", }); }, failure: function() { $.growl.error({ title: "Error updating ingredient suggestion", }); } }); }, deleteIngredient: function(ingredient) { this.dispatch(fluxIngredientSuggestionsStore.constants.DELETE_INGREDIENT, { ingredient: ingredient }); $.ajax({ type: "DELETE", url: "/ingredient_suggestions/" + ingredient.id, success: function(data) { $.growl.notice({ title: "Ingredient suggestion deleted", }); }.bind(this), failure: function() { $.growl.error({ title: "Error deleting ingredient suggestion", }); } }); } }; - Cuối cùng, các đối tượng bao gồm một phương pháp để tạo một đối tượng Flux cất chứa và hành động của mình. Các đối tượng Flux được thông qua với giao diện người dùng dựa trên phản ứng lại trong phần tiếp theo. ```javascript fluxIngredientSuggestionsStore.init = function(ingredients) { var tempStore = { IngredientSuggestionsStore: new fluxIngredientSuggestionsStore.store({ ingredients: ingredients }) }; fluxIngredientSuggestionsStore.flux = new Fluxxor.Flux(tempStore, fluxIngredientSuggestionsStore.actions); } - Tìm hiểu thêm về Fluxxor và làm thế nào nó sẽ giúp bạn dễ dàng xác định các mô hình dữ liệu mà chơi tốt với phản ứng lại. Để biết thêm về các khái niệm, kiểm tra tổng quan Flux của Facebook. - Hiển thị dữ liệu từ database: ```javascript var IngredientSuggestionsEditor = React.createClass({ mixins: [FluxMixin, StoreWatchMixin("IngredientSuggestionsStore")], getStateFromFlux: function() { var flux = this.getFlux(); return { ingredients: flux.store("IngredientSuggestionsStore").getState().ingredients }; }, render: function() { var props = this.props; var ingredients = this.state.ingredients.map(function (ingredient) { return < IngredientSuggestion ingredient={ingredient} key={ingredient.id} flux={props.flux} /> }); return ( <div> {ingredients} </div> ); } }); - Chức năng update, delete dữ liệu: ```javascript var IngredientSuggestion = React.createClass({ mixins: [FluxMixin], getInitialState: function() { return {changed: false, updated: false}; }, render: function() { return ( <div> <a href="#" onClick={this.handleDelete}> < i className="fa fa-times"> </ i> </a> < input onChange={this.handleChange} ref="ingredient" defaultValue={this.props.ingredient.item} /> { this.state.changed ? <span> <a href="#" onClick={this.handleUpdate}>Update</a> <a href="#" onClick={this.handleCancelChange}>Cancel</a> </span> : "" } </div> ) }, handleChange: function() { if ($(this.refs.ingredient.getDOMNode()).val() != this.props.ingredient.item) { this.setState({changed: true}); } else { this.setState({changed: false}); } }, handleUpdate: function(e) { e.preventDefault(); this.getFlux().actions.updateIngredient(this.props.ingredient, $(this.refs.ingredient.getDOMNode()).val()); this.setState({changed: false, updated: true}); }, handleDelete: function(e) { e.preventDefault(); if (confirm("Delete " + this.props.ingredient.item + "?")) { this.getFlux().actions.deleteIngredient(this.props.ingredient); } }, handleCancelChange: function(e) { e.preventDefault(); $(this.refs.ingredient.getDOMNode()).val(this.props.ingredient.item); this.setState({changed: false}); } }); - Render dữ liệu: ```javascript window.loadIngredientSuggestionsEditor = function(ingredients) { /* Define the Fluxxor store (above) */ /* ... */ /* Define the React components (above) */ /* ... */ /* Load the Fluxxor store and render React components to the page */ fluxIngredientSuggestionsStore.init(ingredients); React.render(< IngredientSuggestionsEditor flux={fluxIngredientSuggestionsStore.flux} />, document.getElementById('js-ingredient-suggestions-editor')); } - Cuối cùng là hiển thị dữ liệu thông qua view: ```haml :javascript $(document).ready(function() { window.loadIngredientSuggestionsEditor(#{@ingredients}); }); %h1 Edit ingredient suggestions