有几篇文章描述了在 AJAX 调用后显示 flash 消息(例如,Rails doesn't display flash messages after ajax call 和 How do you handle Rail's flash with Ajax requests?)。
我正在使用 ReactJS与 react-rails并且想要这样做,并且想要利用 React 的动态显示渲染。
所以我正在回答我自己的问题,即在下面使用 ReactJS 时如何在 AJAX 调用后呈现 flash 消息,以此来回答可能遇到此问题的其他人并获得改进它的任何建议。
最佳答案
此实现主要基于有关此主题的其他 SO 帖子(请参阅相关引用资料)。该代码假定 Rails 4.x 具有 Assets 管道,HAML 用于 View ,Bootstrap 用于样式,并使用 react-rails gem 。
(更新:可以在 my blog 找到稍长的讨论)。
布局
这是 app/views/layouts/application.html.haml
文件:
!!!
%html
%head
%title
Demo
= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true
= javascript_include_tag 'application', 'data-turbolinks-track' => true
= csrf_meta_tags
%body
%div.container
%div#flash_messages
= yield
请注意,div
的 ID 为 #flash_messages
。此容器 div 的位置决定了闪存消息的显示位置。
Controller
下面的私有(private)例程简单地将 native 数组数组转换为 header 中的可解析 JSON。
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
after_filter :flash_to_http_header
private
def flash_to_http_header
return unless request.xhr?
return if flash.empty?
response.headers['X-FlashMessages'] = flash.to_hash.to_json
flash.discard # don't want the flash to appear when you reload page
end
end
Javascript (ReactJS)
下面的 javascript 由一个 React 类、一个处理响应 header 中的 flash 消息的全局函数和一个用于完成 AJAX 调用的 JQuery 处理程序组成。它被放入单个 JX 文件(我使用 app/assets/javascripts/react/flash_messages.js.jsx
)以将相关的 JS 功能放在一起。我将在下面对此进行更多讨论。
/** @jsx React.DOM */
var FlashMessages = React.createClass({
getInitialState: function() {
return {messages: this.props.messages};
},
messages: function (messageArray) {
this.replaceState({messages: messageArray});
},
render: function() {
return (
<div className='flash_messages_component'>
{this.state.messages.map(function(message, index) {
_level = message[0];
_text = message[1];
return (
<div key={index} className={this._flash_class(_level)}>
{_text}
</div>
);
}.bind(this))}
</div>
)
},
_flash_class: function(level) {
var _result = 'alert alert-error';
if (level === 'notice') {
_result = 'alert alert-info';
} else if (level === 'success') {
_result = 'alert alert-success';
} else if (level === 'error') {
_result = 'alert alert-error';
} else if (level === 'alert') {
_result = 'alert alert-error';
}
return _result;
}
});
function handleFlashMessagesHeader(node, xhr) {
var _message_array = new Array();
var _raw_messages = xhr.getResponseHeader("X-FlashMessages")
if (_raw_messages) {
var _json_messages = JSON.parse(_raw_messages);
count = 0
for (var key in _json_messages) {
_message_array[count] = new Array();
_message_array[count][0] = key;
_message_array[count][1] = _json_messages[key];
count += 1;
}
}
node.messages(_message_array);
}
$(document).ready(function() {
var dummy = new Array();
var flashDiv = React.render(<FlashMessages messages={dummy} />, $('#flash_messages')[0]);
$(document).ajaxComplete(function(event, xhr, settings) {
handleFlashMessagesHeader(flashDiv, xhr);
});
});
FlashMessages
React 类做了一些事情。首先,它将 Prop 移动到状态。通常这将是一种反模式,但这样做可以让非 React 代码在需要时触发更改。 messages
函数是触发器,旨在由外部 JS 代码调用。 render
的主要处理采用 Rails flash-native array-of-2-element-arrays 数据结构,以将处理保持在最低限度,并允许直接从 View 中使用组件,而不仅仅是 AJAX电话。最后,本地 _flash_class
方法支持 Bootstrap 样式(当然可以根据需要针对其他样式进行调整)。
handleFlashMessagesHeader
是一个全局函数,用于将 JSON 转换回由 Rails Controller 过滤器方法完成的数组数组。请注意,它从 Rails 应用程序 View /布局中获取带有 id 标记的 DOM 元素。
最后一部分旨在在页面加载时运行,因此取决于 JQuery 就绪。 React.render
(正式名称为 React.renderComponent
)被保存到一个全局变量中,以允许直接调用 FlashMessages
对象的 message
方法(使用的 dummy
数组只是在第一次调用时为一个空的 flashes 数组播种——这也可以通过空测试在 React 类中处理)。每当触发 ajaxComplete
时,都会调用 handleFlashMessageHeader
函数并传递 React 对象进行更新。
非 AJAX
因为 React 类采用 native 数组数组,所以 View 可以简单地调用一个
= react-component 'FlashMessages', flash, :div
而不是显示它,但是由于不支持动态响应,它当然用处不大。但是,以任何一种方式调用它的能力为某些用例提供了更大的灵 active 。
关于javascript - 使用 ReactJS 处理 AJAX 调用后的 Rails flash 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26964974/