惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Jina AI
Jina AI
N
Netflix TechBlog - Medium
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
GbyAI
GbyAI
B
Blog
F
Fortinet All Blogs
T
Tailwind CSS Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
Google Developers Blog
A
About on SuperTechFans
C
Check Point Blog
Microsoft Security Blog
Microsoft Security Blog
MyScale Blog
MyScale Blog
B
Blog RSS Feed

Nic Lin's Blog

謝明真 - 高效領導力的課後筆記 NFT 開發實戰!基礎智能合約入門 (3) NFT 開發實戰!基礎智能合約入門 (2) NFT 開發實戰!基礎智能合約入門 (1) 如何自我檢測 log4j CVE 漏洞 Rails 如何在資料寫入時記錄來源 IP 位置 如何經營工程師 Youtube 頻道 - Part 8 營收篇 如何經營工程師 Youtube 頻道 - Part 7 酸民文化篇 如何經營工程師 Youtube 頻道 - Part 5 設備器材篇 如何經營工程師 Youtube 頻道 - Part 4 後製剪輯篇 如何經營工程師 Youtube 頻道 - Part 3 文案企劃篇 如何經營工程師 Youtube 頻道 - Part 2 設備器材篇 如何經營工程師 Youtube 頻道 - Part 1 制訂頻道方向篇 如何經營工程師 Youtube 頻道 - Part 0 Rails 中避免 race condition 的最佳實踐(二) Rails 中避免 race condition 的最佳實踐(一) 10 分鐘整合 google sheet 做自動化開發功能週報 經營 Side Project 300 天所帶來的收穫及挑戰 我的 Youtube 影片製作流程 API 設計時必須注意的 HTTP header 底線問題 如何提升你的程式可讀性之實務技巧(三) 如何提升你的程式可讀性之實務技巧(二) 如何提升你的程式可讀性之實務技巧(一) Ruby 中使用 freeze 優化效能的時機 避免 React 中的 useEffect 無限 render 在 Rails 內輕量使用 Vue Component 的最佳實踐 如何在區域網路用 Docker 架設有 SSL 的 Gitlab 從被問到問人,那些我常問的面試問題 [Rails] 如何漂亮寫出可維護的 query (Maintainable Rails Query) 在已知長度情況下優化 slice 的性能
在Rails 4 上 實作 React.js 入門教學
Nic Lin · 2016-06-22 · via Nic Lin's Blog

React正夯

目前網路上的React.js實作在Rails大概都是在本篇文章產生前的一兩年,雖說時間並不久遠,但是以現今React火熱的程度,這兩年足以產生巨大的差異性更新,筆者搜尋到的範例所使用react-rails Gem版本大約都是(1.0.0.pre),目前卻已經到(1.7.2),舊的範例在執行上或許問題不大,但如果直接寫在新的專案可能就會爆炸,對於學習入門React在Rails上面就會一直不斷撞牆,可能連在Rails上實作React.js的HelloWorld都有問題,所以在無限撞牆之餘,就來寫個簡單的入門教學吧!

關於React.js

React.js是一個”JavaScript library”,相對於Ruby on Rails這種實現了MVC框架來說,我們說React.js更專注於實現V(view),React主要透過兩個原則來建造:Components和States。

Components 可以用其他更小的零件來封裝成組件,然後像插入普通HTML tag一樣,在網頁插入組件。

State驅動了one-way data flow (或稱 one-way binding)單向數據流保持所有資料一致,同時也方便模組化。這樣代表我們的UI將會對每一次的改變做出反應

而State是React放資料Model的其中一種,另一種則是props,這其中的差別請閱讀官方文章

React.js on Rails 實作教學

Source code位置在我的Github,以下的code是修改自官方Tutorial,讓其程式碼能夠順利於Rails運行,其中遇到的問題解決不是很好的部分,在歡迎issue給我。

目前遇到的問題 1. Juery_ujs拔掉之後,出現csrf無法驗證的情況,目前將create的csrf驗證暫時關閉。

創建你的Rails App

這邊筆者使用的版本分別是 Ruby-2.2.3 Rails-4.2.6

1.新建專案 rails new react-tutorial-on-rails 2.切換至專案目錄 cd react-tutorial-on-rails 3.Run bundler bundle install 4.加入Git追蹤 git init . 5.將剛剛生成的專案第一次commit git add . && git commit -m "rails new react-tutorial-on-rails"

1.為了直接對應官方React.js的入門教學,這邊就用Comment做為開始 rails generate scaffold Comment author:string text:text 2.建立資料庫 rake db:migrate 3.Commit存檔 git add . && git commit -m "Generate scaffold Comment and rake db:migrate"

建立一個page頁面作為React渲染的地方

1.建立controller rails generate controller pages index 2.更改首頁指向位置,將程式生出來的get 'pages/index'替換成resources :pages

  resources :pages
  resources :comments
  
  # The priority is based upon order of creation: first created -> highest priority.
  # See how all your routes lay out with "rake routes".
  .......

測試目前的Rails App 運作情形

1.將你的Rails App跑起來 rails server 2.打開你的瀏覽器,並輸入 localhost:3000/pages,檢查是否導入首頁page/index

螢幕快照_2016-06-22_下午3_09_48.png

3.在瀏覽器輸入localhost:3000/comments,測試一下CRUD是否都可以使用了

點擊New comment,任意輸入一些等等會用到的資料。

螢幕快照 2016-06-22 下午1.35.15.png

資料建立完成 螢幕快照 2016-06-22 下午1.36.39.png

4.測試我們使用scaffold所建立的comment在吐json資料時是否正常,可以另開一個Terminal,輸入curl localhost:3000/comments.json

螢幕快照 2016-06-22 下午1.40.55.png

5.到這裡為止都沒有出錯的話,就Commit吧! git add . && git commit -m "Added Pages controller"

安裝React.js所需的Gem

這裡我們使用的Gem是react-rails,詳細請看Github 這個Gem已經幫我們把React.js打包好,並且有一些helper可以做為使用,這邊使用的Gem版本為1.7.2。

1.打開Gemfile 並且加入react-rails gem

    gem 'react-rails'

2.bundle bundle install 3.照的官方文件進行安裝 rails g react:install,會生成的檔案如下

螢幕快照 2016-06-22 下午1.51.19.png

4.移除 jquery_ujs,避免與react_ujs衝突

//= require jquery
-  //= require jquery_ujs <--刪除這行
//= require turbolinks
//= require react
//= require react_ujs
//= require components
//= require_tree .

5.記得重新開啟 rails server

使用React官方的Tutorial,寫一些React code

這邊我們建議將React官方的Tutorial看過一遍,並且可以參考實作的React-Tutorial Github)

1.依照官方範例創建以下四隻檔案

var Comment = React.createClass({
  rawMarkup: function() {
    var md = new Remarkable();
    var rawMarkup = md.render(this.props.children.toString());
    return { __html: rawMarkup };
  },

  render: function () {
    return (
      <div className="comment panel panel-default">
        <div className="panel-heading">
          <h3 className="panel-title">
            {this.props.author} 說了:
          </h3>
        </div>
        <div className="panel-body">
          {this.props.text}
        </div>
      </div>
    )
  }
});
var CommentBox = React.createClass({
  getInitialState: function () {
    return JSON.parse(this.props.presenter);
  },

  loadCommentsFromServer: function() {
    $.ajax({
      url: this.props.url,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({ comments: data });
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
  },

  handleCommentSubmit: function ( formData, action ) {
    $.ajax({
      data: { comment: formData},
      url: action,
      type: "POST",
      dataType: "json",
      success: function ( data ) {
        this.setState({ comments: data });
      }.bind(this)
    });
  },

  componentDidMount: function() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, 2000);
  },

  render: function () {
    return (
      <div className="comment-box">
        <img src={ this.props.imgSrc } alt={ this.props.imgAlt } />
        <CommentList comments={ this.state.comments } />
        <hr />
        <h2>新增留言</h2>
        <CommentForm form={ this.state.form } onCommentSubmit={ this.handleCommentSubmit } />
      </div>
    );
  }
});
var CommentForm = React.createClass({
  getInitialState: function() {
    return {author: '', text: ''};
  },
  handleAuthorChange: function(e) {
    this.setState({author: e.target.value});
  },
  handleTextChange: function(e) {
    this.setState({text: e.target.value});
  },
  handleSubmit: function(e) {
    e.preventDefault();
    var author = this.state.author.trim();
    var text = this.state.text.trim();
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text});
    this.setState({author: '', text: ''});
  },
  render: function() {
    return (
      <div className="panel panel-default">
        <div className="panel-heading">聊聊吧</div>
        <div className="panel-body">
          <form className="commentForm " onSubmit={this.handleSubmit} action={ this.props.form.action } acceptCharset="UTF-8" method="post" onSubmit={ this.handleSubmit } >
            <div className="form-group">
              <label className="control-label" forName="authorInput">暱稱</label>
              <input type="text" id="authorInput" className="form-control" placeholder="Your name" ref="author" value={this.state.author} onChange={this.handleAuthorChange}/>
            </div>
            <div className="form-group">
              <label className="control-label" forName="commentInput">留言</label>
              <textarea className="form-control" id="commentInput" rows="3" placeholder="Say something..." ref="text" value={this.state.text} onChange={this.handleTextChange}/>
            </div>
            <input type="submit" className="btn btn-primary" value="Post" />
          </form>
        </div>
      </div>
    );
  }
});

var CommentList = React.createClass({
  render: function () {
    var commentNodes = this.props.comments.map(function ( comment ) {
      return <Comment author={ comment.author } text={ comment.text } key={ comment.id } />
    });

    return (
      <div className="comment-list">
        { commentNodes }
      </div>
    )
  }
});

2.利用React gem的helper 呼叫component

  <%= react_component('CommentBox', {:presenter => @presenter.to_json}, {:prerender => true}) %>

3.處理json所需的資料

class PagesController < ApplicationController
  skip_before_filter :verify_authenticity_token, only: [:create]
  def index
    @presenter = {
      :comments => Comment.last(5),
      :form => {
        :action => comments_path,
        :csrf_param => request_forgery_protection_token,
        :csrf_token => form_authenticity_token
      }
    }
  end

  def create
    @comment = Comment.new(comment_params)
    @comment.save

    if request.xhr?
      render :json => Comment.last(5)
    else
      redirect_to comments_path
    end
  end

  private
  def comment_params
    params.require(:comment).permit(:author, :text)
  end
end

4.於瀏覽器輸入 http://localhost:3000/pages 進行測試,沒意外會看到以下畫面,可以利用chrome進行檢查,看react生出的html

螢幕快照 2016-06-22 下午2.28.05.png

5.以上步驟都沒問題請記得commitgit commit -am “React component loads”

bonus: 加入bootstrap讓畫面更好看吧

1.加入bootstrap-sass

+  gem 'bootstrap-sass'

2.安裝Gem bundle install

3.安裝bootstrap所需javascript

+ //= require bootstrap-sprockets

4.安裝bootstrap所需CSS,並將原本的application.css檔名改為application.css.scss

+ @import "bootstrap-sprockets";
+ @import "bootstrap";

5.利用bootstrap的css修正畫面

<div class="container">
<h3>React</h3>
<hr>
  <%= react_component('CommentBox', {:presenter => @presenter.to_json}, {:prerender => true}) %>
</div>

6.完成並且commit git add . & git commit -m "Added Bootstrap sass"