原文: 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/322gem '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
。
这会
创建一个components.js文件。
创建
app/assets/javascripts/components/
目录。
现在在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.coffee
,app/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
用来创建新的更新订阅,并传递我们想要听的频道。它接受下面的回调钩子方法。
connected
:订阅连接成功。这里我们使用perform
方法来调用相关操作,并将数据传递给方法。perform('follow', {message_id: this.message_id}), 1000)
,电话CommentsChannel#follow(data)
。received
:我们收到了来自Rails的新数据通知。在这里我们采取行动来更新我们的组件。我们已经通过了updateCommentList: this.updateCommentList
,这是一个用从Rails接收的数据调用的Component方法。
完整的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的完整工作示例可以在这里找到。
作者:非常尛貝
链接:https://www.jianshu.com/p/fefb47eebc79