Ruby & RailsRubyRuby on Rails

通过Rails Action Cable使用ReactJS

2018-02-27  本文已影响6人  6df0d073b6fb

原文: http://www.codedata.cn/hacknews/151968968336927532
Action Cable在Ruby on Rails应用程序中通过websocket实现实时通信。它允许构建实时应用程序,如聊天,状态更新等。

Action Cable + React

Action Cable提供实时通信, ReactJS是管理客户端视图复杂性的好工具。他们一起可以很容易地开发出快速的Web应用程序,前端的状态管理则不需要太多的编码。

无论何时数据发生变化,Action Data即刻提供新数据,新数据显示在视图中,而无需用户通过ReactJS对应用程序进行任何操作。

集成React

官方的Action Cable Example是一个聊天应用程序。我们将使用ReactJS构建相同的应用程序。

首先按照上述说明使用Action Cable获取正在运行的聊天应用程序。

现在聊天应用程序正在运行,让我们开始向应用程序添加ReactJS。

请注意,我们还发布了一些关于学习ReactJS 的 视频。如果你有兴趣,请检查他们。

第1步 - 将所需的gems添加到Gemfile

#  react-rails isn't compatible yet with latest Sprockets.
#  https://github.com/reactjs/react-rails/pull/322
gem 'react-rails', github: 'vipulnsward/react-rails', branch: 'sprockets-3-compat'

#  Add support to use es6 based on top of babel, instead of using coffeescript
gem 'sprockets-es6'

第2步 - 添加必需的JavaScript文件

按照react-rails的安装和运行rails g react:install

这会

现在在application.js中放入以下几行代码:

//= require react
//= require react_ujs
//= require components

确保你app/assets/javascripts/application.js看起来像这样

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require react
//= require react_ujs
//= require components
//= require cable

//= require channels
//= require_tree .

第3步 - 设置操作Action Cable 开始监听事件

我们将使用es6,所以让我们替换文件app/assets/javascripts/channels/index.coffeeapp/assets/javascripts/channels/index.es6并添加以下代码。

var App = {};
App.cable = Cable.createConsumer('ws://localhost:28080');

还要删除app/assets/javascripts/channels/comments.coffee用于设置订阅的文件。我们将从我们的React组件中完成此设置。

第4步 - 创建CommentList React组件

将以下代码添加到app/assets/javascripts/components/comments_list.js.jsx

var CommentList = React.createClass({
  getInitialState(){
    let message = JSON.parse(this.props.message);
    return {message: message};
  },

  render() {
    let comments = this.state.message.comments.map((comment) => {
      return this.renderComment(comment);
    });

    return (
      <div>{comments}</div>
    );
  },

  renderComment(comment) {
    return (
      <article key={comment.id}>
        <h3>Comment by { comment.user.name }</h3>
        <p>{ comment.content }</p>
      </article>
    );
  }
});

这里我们定义了一个简单的组件来显示与消息相关的评论列表。消息和相关评论作为道具传递。

第5步 - 创建消息JSON构建器

接下来我们需要设置需要传递给组件的数据。

将以下代码添加到app/views/messages/_message.json.jbuilder

json.(message, :created_at, :updated_at, :title, :content, :id)
json.comments(message.comments) do |comment|
  json.extract! comment, :id, :content
  json.user do
    json.extract! comment.user, :id, :name
  end
end

这会将JSON数据推送到我们的CommentList组件。

第6步 - 创建Rails视图来显示组件

我们现在需要设置我们对消息和评论显示的看法。

我们需要表单来创建新的消息评论。这已经存在,app/views/comments/_new.html.erb我们将按原样使用它。

<%= form_for [message, Comment.new], remote: true do |form| %>
  <%= form.text_area :content, size: '100x20' %><br>
  <%= form.submit 'Post comment' %>
<% end %>

在创建评论之后,我们需要用新的表单替换当前表单,在视图处理之后进行处理。

从文件中app/views/comments/create.js.erb 删除包含以下代码的行。请注意,下面的行需要删除。

$('#comments').append('<%=j render @comment %>');

我们需要显示消息详细信息并呈现组件以显示注释。在app/views/messages/show.html.erb之前插入以下代码<%= render 'comments/comments', message: @message %>

<%= react_component 'CommentList', message: render(partial: 'messages/message.json', locals: {message: @message}) %>

插入代码后会看起来像这样。

<h1><%= @message.title %></h1>
<p><%= @message.content %></p>
<%= react_component 'CommentList', message: render(partial: 'messages/message.json', locals: {message: @message}) %>
<%= render 'comments/new', message: @message %>

注意我们如何渲染CommentList,它基于我们创建的jbuilder视图中的消息json内容。

第7步 - 设置订阅从React Component收听操作电缆

要收听评论的新更新,我们需要从Action Cable设置订阅。

将以下代码添加到CommentList组件。

setupSubscription(){

  App.comments = App.cable.subscriptions.create("CommentsChannel", {
    message_id: this.state.message.id,

    connected: function () {
      setTimeout(() => this.perform('follow',
                                    { message_id: this.message_id}), 1000 );
    },

    received: function (data) {
      this.updateCommentList(data.comment);
    },

    updateCommentList: this.updateCommentList

    });
}

我们还需要在Rails上设置相关的AC通道代码。

在下面的代码中存在 app/channels/comments_channel.rb

class CommentsChannel < ApplicationCable::Channel
  def follow(data)
    stop_all_streams
    stream_from "messages:#{data['message_id'].to_i}:comments"
  end

  def unfollow
    stop_all_streams
  end
end

在我们的React Component中,我们App.cable.subscriptions.create用来创建新的更新订阅,并传递我们想要听的频道。它接受下面的回调钩子方法。

完整的React组件

以下是我们的完整组件的外观。

var CommentList = React.createClass({
  getInitialState(){
    let message = JSON.parse(this.props.message);
    return {message: message};
  },

  render() {
    let comments = this.state.message.comments.map((comment) => {
      return this.renderComment(comment);
    });

    return (
        <div>{comments}</div>
    );
  },

  renderComment(comment) {
    return (
        <article key={comment.id}>
          <h3>Comment by { comment.user.name } </h3>
          <p>{ comment.content }</p>
        </article>
    );
  },

  componentDidMount() {
    this.setupSubscription();
  },

  updateCommentList(comment) {
    let message = JSON.parse(comment);
    this.setState({message: message});
  },

  setupSubscription() {

    App.comments = App.cable.subscriptions.create("CommentsChannel", {
      message_id: this.state.message.id,

      connected: function () {
        // Timeout here is needed to make sure Subscription
        // is setup properly, before we do any actions.
        setTimeout(() => this.perform('follow',
                                      {message_id: this.message_id}),
                                      1000);
      },

      received: function(data) {
        this.updateCommentList(data.comment);
      },

      updateCommentList: this.updateCommentList
    });
  }
});

第7步 - 创建新评论时广播消息。

我们的最后一部分是广播新的更新消息给订阅了频道的听众。

将以下代码添加到 app/jobs/message_relay_job.rb

class MessageRelayJob < ApplicationJob
  def perform(message)
    comment = MessagesController.render(partial: 'messages/message',
                                         locals: {message: message})
    ActionCable.server.broadcast "messages:#{message.id}:comments",
                                 comment: comment
  end
end

然后从Comment模型中调用,

将此行添加到Comment模型文件app/model/comment.rb

after_commit { MessageRelayJob.perform_later(self.message) }

我们在这里使用消息中继,并将摆脱现有的评论中继文件app/jobs/comment_relay_job.rb。我们还将从Comment模型中删除对CommentRelayJob的引用,因为after_commit现在调用该模型MessageRelayJob

概要

希望我们已经表明,Action Cable未来将成为ReactJS的好朋友。只有时间会给出答案。

Action Cable + ReactJS的完整工作示例可以在这里找到。

上一篇下一篇

猜你喜欢

热点阅读