Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Modern Single Page Applications

Modern Single Page Applications

Modern Single Page Applications

vipulnsward

July 06, 2016
Tweet

More Decks by vipulnsward

Other Decks in Programming

Transcript

  1. What is an API Application? https://developer.github.com/v3/emojis/ # GET /emojis
 


    {
 "+1": "https://github.global.ssl.fastly.net/images/icons/emoji/+1.png?v5",
 "-1": "https://github.global.ssl.fastly.net/images/icons/emoji/-1.png?v5",
 "101": "https://github.global.ssl.fastly.net/images/icons/emoji/100.png?v5",
 "1234": "https://github.global.ssl.fastly.net/images/icons/emoji/1234.png?v5",
 "8ball": "https://github.global.ssl.fastly.net/images/icons/emoji/8ball.png?v5",
 "a": "https://github.global.ssl.fastly.net/images/icons/emoji/a.png?v5",
 "ab": "https://github.global.ssl.fastly.net/images/icons/emoji/ab.png?v5"
 }

  2. Why Rails? Rails Development Environment Nifty Testing Inbuilt security Parameter

    parsing Code Reloads anyone? Header responses Other Rails Goodness: AR, AM, AJ, ACa
  3. What this does Slimmed down middleware* stack No views &

    cruft from AV ApplicationController < ActionController::API

  4. Default Stack - Rack::Sendfile
 - ActionDispatch::Static
 - ActionDispatch::Executor
 - ActiveSupport::Cache::Strategy::LocalCache::Middleware


    - Rack::Runtime
 - ActionDispatch::RequestId
 - Rails::Rack::Logger
 - ActionDispatch::ShowExceptions
 - ActionDispatch::DebugExceptions
 - ActionDispatch::RemoteIp
 - ActionDispatch::Reloader
 - ActionDispatch::Callbacks
 - ActiveRecord::Migration::CheckPending
 - Rack::Head
 - Rack::ConditionalGet
 - Rack::ETag
  5. ActionController::API - ActionController::UrlFor
 - ActionController::Redirecting
 - AbstractController::Rendering and ActionController::ApiRendering
 -

    ActionController::Renderers::All
 - ActionController::ConditionalGet
 - ActionController::BasicImplicitRender
 - ActionController::StrongParameters
 - ActionController::ForceSSL
 - ActionController::DataStreaming
 - AbstractController::Callbacks
 - ActionController::Rescue
 - ActionController::Instrumentation
 - ActionController::ParamsWrapper
  6. Connections # app/channels/application_cable/connection.rb
 module ApplicationCable
 class Connection < ActionCable::Connection::Base
 identified_by

    :current_user
 
 def connect
 self.current_user = find_verified_user
 end
 
 protected
 def find_verified_user
 if current_user = User.find_by(id: cookies.signed[:user_id])
 current_user
 else
 reject_unauthorized_connection
 end
 end
 end
 end
  7. Channels # app/channels/application_cable/channel.rb
 module ApplicationCable
 class Channel < ActionCable::Channel::Base
 end


    end # app/channels/update_channel.rb
 class UpdateChannel < ApplicationCable::Channel
 end # app/channels/chat_channel.rb
 class ChatChannel < ApplicationCable::Channel
 end
 

  8. Channels # app/channels/chat_channel.rb
 class ChatChannel < ApplicationCable::Channel
 # Called when

    the consumer has successfully
 # become a subscriber of this channel.
 def subscribed
 end
 
 def my_custom_action
 end
 
 def user_posted_something
 end
 end

  9. Consumer Connection // app/assets/javascripts/cable.js
 //= require action_cable
 //= require_self
 //=

    require_tree ./channels
 
 (function() {
 this.App || (this.App = {});
 
 App.cable = ActionCable.createConsumer();
 }).call(this);
  10. Streams # app/channels/chat_channel.rb
 class ChatChannel < ApplicationCable::Channel
 def subscribed stop_all_streams


    stream_from "chat_#{params[:room]}"
 end
 end # app/channels/comments_channel.rb class CommentsChannel < ApplicationCable::Channel
 def subscribed
 post = Post.find(params[:id])
 stream_for post
 end
 end

  11. Client Side Subscription App.chatChannel = App.cable.subscriptions.create({ channel: "ChatChannel", room: "Best

    Room" }, {
 //Entry point when some data will be received received: function (data) {
 return this.appendLine(data);
 }, 
 appendLine: function (data) {
 var html;
 html = this.createLine(data);
 return $("[data-chat-room='Best Room']").append(html);
 }, 
 createLine: function (data) {
 return "data[ "sent_by" ] + “: "+ data[ "body" ];
 }
 });
  12. A Simple Component var HelloMessage = React.createClass({
 render: function() {


    return <div>Hello {this.props.name}</div>;
 }
 });
 
 ReactDOM.render(<HelloMessage name="John" />, mountNode);

  13. A Simple Component var Timer = React.createClass({
 getInitialState: function() {


    return {secondsElapsed: 0};
 },
 tick: function() {
 this.setState({secondsElapsed: this.state.secondsElapsed + 1});
 },
 componentDidMount: function() {
 this.interval = setInterval(this.tick, 1000);
 },
 componentWillUnmount: function() {
 clearInterval(this.interval);
 },
 render: function() {
 return (
 <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
 );
 }
 });
 
 ReactDOM.render(<Timer />, mountNode);

  14. console.log('Start')
 var App = React.createClass({
 componentWillMount: function(){
 console.log('componentWillMount');
 },
 


    componentDidMount: function(){
 console.log('componentDidMount');
 },
 
 getInitialState: function(){
 return { status: true}
 },
 
 getDefaultProps: function(){
 return {name: 'John'};
 },
 
 …

  15. …
 
 render: function() {
 console.log('render');
 return <h1 onClick={this.toggleState}>
 {this.state.status.toString()}


    </h1>
 },
 
 componentWillUnmount: function(){
 console.log('componentWillUnmount')
 },
 
 toggleState: function() {
 this.setState({status: !this.state.status})
 }
 });
  16. … componentDidMount() {
 this.setupSubscription();
 }
 … 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.bind(this)
 
 });
 
 }