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

From Back to Front: Rails To ReactJS, Flux, Relay/GraphQL

Khor
November 22, 2015

From Back to Front: Rails To ReactJS, Flux, Relay/GraphQL

React Family: ReactJS/Flux/RelayJS/GraphQL

* What makes them interesting?
* What are they? How they work together?
* How do I get started easily?
* Should I use them all?

Khor

November 22, 2015
Tweet

Other Decks in Programming

Transcript

  1. Outline • React Family: ReactJS/Flux/RelayJS/GraphQL • What makes them interesting?

    • What are they? How they work together? • How do I get started easily? • Should I use them all? • IMPORTANT: How to get them onto Rails
  2. React/Flux/Relay/GraphQL: In A Sentence Each • React: UI • Flux:

    Data Flow • GraphQL: Data Retrieval • Relay: Component-Data Co-location
  3. React/Flux/Relay/GraphQL: Common Goal Improve software quality given the same development

    time • Easy to understand & debug • Less prone to error
  4. React/Flux/Relay/GraphQL: Common Approach Simplify abstraction to push common tasks/code organization

    to pattern/framework • Easy to understand & debug • Less prone to error
  5. React (cont.) Abstraction Each React element knows: • The data

    it needs • How to render itself with HTML fragments • The data it passes to its children
  6. React (cont.) jQuery: You need to find all the pieces

    of code that modified the UI in error
  7. Imperative vs. Functional: Coding • Imperative: ◦ Example: jQuery code

    ▪ Code is likely in a monolithic Javascript ▪ Hold element ids for where each piece of data should be shown ▪ Retrieves element and display data ▪ Complex model requires customized code: • Find pieces of data, and update pieces of element • Functional: ◦ Example: React code ▪ Code is contained within each React element: ▪ Each React element declares which part of data to pass on to children ▪ Each React element declares how to render data it receives ▪ Simplified model reduces code relinquish more to framework: • Provide data to top view, and cascading views redraws themselves
  8. Functional vs. Imperative: Benefits • Imperative: ◦ Complex model requires

    customized code ▪ Dig through customized code to understand relationships ▪ Different pieces of code to initialize UI, and update based on interaction • Functional: ◦ Simplified model reduces code relinquish more to framework ▪ Relationship and data-flow is top-down ▪ Same piece of code to initialize, and update UI
  9. React: Code var DATA = [ { category: 'Sporting Goods',

    products: [ {price: '$49.99', stocked: true, name: 'Football'}, {price: '$9.99', stocked: true, name: 'Baseball'}, {price: '$29.99', stocked: false, name: 'Basketball'}, ], }, { category: 'Electronics', products: [ {price: '$99.99', stocked: true, name: 'iPod Touch'}, {price: '$399.99', stocked: false, name: 'iPhone 5'}, {price: '$199.99', stocked: true, name: 'Nexus 7'}, ], }, ];
  10. React: Code (cont.) // app/assets/javascripts/components/product.jsx var ProductTable = React.createClass( render:

    function() { var rows = []; this.props.data.forEach(function(dataElem) { rows.push(<ProductCategoryRow category={dataElem.category} … />); dataElem.products.forEach(function(product) { rows.push(<ProductRow product={product} … />); }); ... var DATA = [ { category: 'Sporting Goods', products: [ {name: 'Football', ...}, {name: ’Baseball’, ... }, ... ], }, { category: 'Electronics', products: [ {name: 'iPod Touch', ...}, {name: ‘iPhone 6’, …}, ... ], }, ];
  11. React: Code (cont.) // app/assets/javascripts/components/product.jsx var ProductRow = React.createClass({ render:

    function() { return ( <tr> <td>{this.props.product.name}</td> <td>{this.props.product.price}</td> </tr> ); } });
  12. React: Summary Simplify abstraction • UI ◦ Shove data for

    entire UI from the top component ◦ Each component render itself with data for self ◦ Each component pass data to child ◦ To change component, just change data Framework • Handle initializing/updating UI with the right pieces of data How • Re-drawing all UI pieces efficiently
  13. Tracing Loops Difficult: • Tons of log entries ◦ Lots

    of things to look through ◦ Scrolling is laggy • Cannot just look at snapshot for messy loops
  14. MVC Looping the Loop Explosion of flows Error in UI

    Depending on where you look in the trace, you may think orange or bold loop A loop resulting in another loop
  15. MVC Simultaneous Loops Explosion of flows Error in UI Tracing

    is difficult; seeing two traces A loop resulting in multiple other loops concurrently
  16. Flux (cont.) Courtesy: http://fluxxor.com/what-is-flux.html Take Action Action Done Action Done

    State Update • Throttles one Action at a time • waitsFor() • Synchronous tasks only • State and logic co-located
  17. Side-by-side • Structured growth (no path explosion): ◦ Parallel stores

    lead to single top view ◦ Single-parent cascading views MVC Flux React
  18. Side-by-side • Structured growth (no path explosion): ◦ Parallel stores

    lead to single top view ◦ Single-parent cascading views • Controllers-Models collapsed into Stores to co- locate logic & state MVC Flux React Store Store
  19. With Flux Error in UI Only one trace at a

    time • Dispatcher throttles Actions A loop resulting in multiple other loops concurrently
  20. Action Creator TodoActions: { create: function(text) { // Take some

    action, e.g., call REST API AppDispatcher.dispatch({ actionType: TodoConstants.TODO_CREATE, // Basically ‘create’ text: text }); }, …. }
  21. Store AppDispatcher.register(function(action) { // action is passed in by Action

    Creator var event = action.event; switch(action.actionType) { case TodoConstants.TODO_CREATE: // Do whatever, e.g., update local store data or fetch fresh data from server TodoStore.emitChange(); break; …. } } register
  22. Store (cont.) var TodoStore = assign({}, EventEmitter.prototype, { // EventEmitter

    provides emit, on, removeListener, etc. methods addChangeListener: function(callback) { this.on(CHANGE_EVENT, callback); }, removeChangeListener: function(callback) { this.removeListener(CHANGE_EVENT, callback); }, emitChange: function() { this.emit(CHANGE_EVENT); }, ... } register
  23. Controller-View // This is where React is used var TodoApp

    = React.createClass({ componentDidMount: function() { TodoStore.addChangeListener(this._onChange); }, componentWillUnmount: function() { TodoStore.removeChangeListener(this._onChange); }, _onChange: function() { this.setState(TodoStore.getData()); }, ... } register
  24. Flux: More Pattern than Framework • Many implementations • Flux:

    ◦ By Facebook • Redux: ◦ Not pure Flux per se, but embraces its spirit ◦ Server-side rendering built-in ◦ Growing super-fast • Alt: ◦ Pure Flux compliant ◦ Well-documented, great community ◦ Server-side rendering built-in
  25. Flux Documentation Quirks • Uses native dispatcher, not the official

    Facebook dispatcher ◦ Use official Facebook dispatcher • Does not use Flux-Utils ◦ Use Flux-Utils to create Stores without code duplication Rails with pure Flux: https://medium.com/@khor/back-to-front-rails-to-facebook-s-flux-ae815f81b16c
  26. GraphQL (cont.) API Endpoint query { store(email: "[email protected]") { name,

    address } } store(email: “[email protected]”) { name: ‘Hello Shop’, address: ‘1-3-1 Aoyama’ }
  27. GraphQL (cont.) API Endpoint query { store(email: "[email protected]") { categories

    { name, products { name, price, stock } } } } store { categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price:, stock: 50 }, … }, ... ] } From React example
  28. GraphQL (cont.) API Endpoint query { store(email: "[email protected]") { categories

    { name, products { name, price, stock } } } } store { categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price:, stock: 50 }, … }, ... ] } Single endpoint Nested data query Client-specified query Data in 1 round-trip
  29. GraphQL (cont.) REST API: • 3 endpoints: ◦ Endpoint for

    Store ◦ Endpoint for Category ◦ Endpoint for Product • Server-controlled query ◦ Query for store returns email, name, address, etc. whether you want it or not • Multiple round-trips vs. impure-REST/endpoint proliferation ◦ Get Store, get each Category, get each Product in each Category ◦ Lumping them together creates view-specific endpoints
  30. GraphQL: Schema # app/graph/types/query_type.rb field :store do type StoreType #

    Shape of this type argument :email, !types.String, "Email of Store owner" ... # Retrieve data resolve -> (obj, args, ctx) do Store.find_by_email(args[:email]) # ActiveRecord stuff end end query { store(email: "[email protected]") { name, address } }
  31. GraphQL: Schema (cont.) # app/graph/types/store_type.rb StoreType = GraphQL::ObjectType.define do name

    "Store" description "Store Data" … field :name, !types.String, "Store name" # From ActiveRecord field field :address, !types.String, "Store address" # From ActiveRecord field field :categories, !types[CategoryType], “Category list” # From ActiveRecord field end query { store(email: "[email protected]") { name, address } }
  32. GraphQL: Schema (cont.) # app/graph/types/store_type.rb StoreType = GraphQL::ObjectType.define do name

    "Store" description "Store Data" … field :name, !types.String, "Store name" # From ActiveRecord field field :address, !types.String, "Store address" # From ActiveRecord field field :categories, !types[CategoryType], “Category list” # From ActiveRecord field end query { store(email: "[email protected]") { categories { name, products { name, price, stock } } } }
  33. GraphQL: Schema (cont.) # app/graph/types/category_type.rb CategoryType = GraphQL::ObjectType.define do name

    "Category" description "Category Data" … field :name, !types.String, "Category name" # From ActiveRecord field field :products, !types[ProductType], “Product list” # From ActiveRecord field ... end query { store(email: "[email protected]") { categories { name, products { name, price, stock } } } }
  34. GraphQL: Summary Simplify: • Efficient request for data that you

    need from server endpoint Framework • A single API endpoint to respond to query • Query language that enables client to specify data required, ala SQL • No over-fetch • Request all data in a single query
  35. GraphQL/Relay Enabled gem ‘graphql-ruby’ I speak GraphQL/Relay API Endpoint gem

    ‘graphql-relay-ruby’ Relay Layer ‘react-relay’
  36. Relay: Summary Simplify • Data fetching related stuff ◦ Show

    ‘Loading….’ ◦ Data re-fetching ◦ Caching ▪ Figuring out batching, reading/writing caching, fetching only missing pieces ▪ NOTE: Caching is NOT new but handling caching for hierarchical data is rather new ◦ Managing errors, retry failed requests ◦ Optimistic updates ◦ Pagination Framework • Use GraphQL to fetch all required data declaratively • Handle all the above
  37. How To Get Started Easily? • Make one piece of

    UI React • Make another piece React • Repeat until SPA
  38. Which Should I Use Partly from: https://facebook.github.io/react/blog/2015/02/20/introducing-relay-and-graphql.html Flux Relay/GraphQL Multiple

    stores (one per domain) Single store (GraphQL server) Explicit subscription Implied subscription based on data required Actions (possibly with AJAX) Mutations (query with changes) REST API pros, and cons Efficient data handling (batching, caching, no over-fetching, etc.) More customized coding Generic framework for data access, updates, etc. Prefer imperative debugging Love magic, abstractions, and puzzle debugging
  39. Other Stuff • React ◦ Must all user-interaction go to

    top? Must top do all data manipulation? • GraphQL ◦ Can I just use GraphQL? Do I need Relay? • Relay ◦ How to modify Model without AJAX? ◦ There is no gem?
  40. Primary Resources Thinking in React: https://facebook.github.io/react/docs/thinking-in-react.html Flux Best Practices: https://facebook.github.io/flux/docs/flux-utils.html

    Nested Relay Components: https://facebook.github.io/react/blog/2015/03/19/building-the-facebook-news-feed-with-relay.html
  41. Practical Resources Rails with pure Flux: https://medium.com/@khor/back-to-front-rails-to-facebook-s-flux-ae815f81b16c Relay/GraphQL on Rails:

    https://medium.com/@khor/relay-facebook-on-rails-8b4af2057152 Relay/GraphQL Rails Starter Kit: https://github.com/nethsix/relay-on-rails
  42. References Flux Comparisons: • https://medium.com/social-tables-tech/we-compared-13-top-flux-implementations-you-won-t-believe- who-came-out-on-top-1063db32fe73 • http://jamesknelson.com/which-flux-implementation-should-i-use-with-react/ Introduction to

    GraphQL: http://facebook.github.io/react/blog/2015/02/20/introducing-relay-and-graphql.html Thinking In GraphQL: https://facebook.github.io/relay/docs/thinking-in-graphql.html Thinking In Relay: https://facebook.github.io/relay/docs/thinking-in-relay.html