通过Rails Action Cable使用ReactJS
原文: 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
。
这会
- 创建一个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的完整工作示例可以在这里找到。