javascript - 使用 ReactJS 处理 AJAX 调用后的 Rails flash 消息

标签 javascript ruby-on-rails ajax reactjs

有几篇文章描述了在 AJAX 调用后显示 flash 消息(例如,Rails doesn't display flash messages after ajax callHow do you handle Rail's flash with Ajax requests?)。

我正在使用 ReactJSreact-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/

相关文章:

jQuery UI Sortable - 单击按钮时保存顺序

jquery - XMLHttpRequest、jQuery.ajax、jQuery.post、jQuery.get 之间有什么区别

ruby-on-rails - 允许当前用户删除其帐户

ruby-on-rails - ActiveModel::ForbiddenAttributesError Rails 4

javascript - Cytoscape.js 折叠所有传入和传出节点

javascript - jQuery :not(this) unexpected behavior

ruby-on-rails - 用户回形针重命名上传的文件

javascript - jQuery Mobile 页面丢失 JavaScript 文件

javascript - 使用 Javascript 为内容设置样式

javascript - 如何让for循环等待函数在javascript中执行