Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Missing Pages:
ReactJS/Flux/GraphQL/RelayJS
Khor, @neth_6, re:Culture
Shed light on assumptions/details
glossed over in FB’s docs
Agenda
● Using pure Flux
● GraphQL
○ Sans RelayJS
○ Setup GraphQL on non-NodeJS servers
● RelayJS
○ Revisiting ReactJS: Re...
React Family: In a Few Words ...
● ReactJS: UI data & rendering
● Flux: Data flow & code organization
● GraphQL: Single AP...
GraphQL: Sans RelayJS
GraphQL
I speak GraphQL
API Endpoint
Single Endpoint can Deliver all data
store(email: “admin@abc.com”) {
name: ‘Hello Sho...
GraphQL (cont.)
API Endpoint
query {
store(email: "admin@abc.com") {
name,
address
}
}
GraphQL (cont.)
API Endpoint
query {
store(email: "admin@abc.com") {
name,
address
}
}
store(email: “admin@abc.com”) {
nam...
GraphQL (cont.)
API Endpoint
query {
store(email: "admin@abc.com") {
categories {
name,
products {
name, price, stock
}
}
...
GraphQL (cont.)
API Endpoint
query {
store(email: "admin@abc.com") {
categories {
name,
products {
name, price, stock
}
}
...
GraphQL: Setup
GraphQL: Like all Client-Server
Browser
http(s)
Any Server
GraphQL: Over HTTP(S)
Browser
GraphQL
Server
Bundled
JS
GraphQL
over
http(s), etc.
Any Server
GraphQL Over http(s)
GraphQL over http
GraphQL: Enabling the Server
Browser
GraphQL
Server
Bundled
JS
GraphQL
over
http(s), etc.
Any Server
Server
Libraries
grap...
GraphQL: JS Code
Browser
GraphQL
Server
Bundled
JS
Bundled
JS
Any Server
GraphQL
over
http(s), etc.
Server
Libraries
graph...
GraphQL: Required JS Libraries
Browser
GraphQL
Server
Bundled
JS
Bundled
JS
Any Server
JS Libraries
react
react-dom
graphq...
GraphQL: Bundling Your JS Code
Browser
GraphQL
Server
Bundled
JS
Bundled
JS
Any Server
JS Libraries
react
react-dom
graphq...
ReactJS (Review)
ReactJS
● Single-Page Application (SPA)
Courtesy: https://facebook.github.io/react/docs/thinking-in-react.html
Hello Shop
ReactJS (cont.)
● Single-Page Application (SPA)
● Cascading Views
Hello Shop
ReactJS (cont.)
● Single-Page Application (SPA)
● Cascading Views
Hello Shop
React (cont.)
● Single-Page Application (SPA)
● Cascading Views
Hello Shop
Hierarchical Views => GraphQL Hierarchical Data
ReactJS (cont.)
Abstraction
Each ReactJS element knows:
● The data it needs
● How to render itself with HTML fragments
● T...
React (cont.)
● Single-Page Application (SPA)
● Cascading Views
Fetch
Data
Hello Shop
React (cont.)
● Single-Page Application (SPA)
● Cascading Views
Hello Shop
React (cont.)
● Single-Page Application (SPA)
● Cascading Views
Hello Shop
Passing Data to Children
this.props = {
store:
name: ‘Hello Shop’
categories: [
{
name: 'Sporting Goods',
items: [
{ name:...
Not so Loose Coupling, Not so High Reuse
● Parent needs to know about child’s data
○ Need to fetch data for children
○ Nee...
RelayJS: Component-Data Co-location
Reduce coupling, increase reusability
GraphQL
I speak GraphQL
API Endpoint
Single Endpoint can Deliver all data
store(email: “admin@abc.com”) {
name: ‘Hello Sho...
Sample App: Refresh your Memory
Hello Shop
Sample App: Simplified
Hello Shop
RelayJS: Component & Data Co-location
store(email: “admin@abc.com”) {
name: ‘Hello Shop’,
address: ‘1-3-1 Aoyama’
categori...
store(email: “admin@abc.com”) {
name: ‘Hello Shop’,
address: ‘1-3-1 Aoyama’
categories: [
{
name: ‘Sporting Goods’,
produc...
store(email: “admin@abc.com”) {
name: ‘Hello Shop’,
address: ‘1-3-1 Aoyama’
categories: [
{
name: ‘Sporting Goods’,
produc...
Passing Data to Children
this.props = {
store:
name: ‘Hello Shop’
categories: [
{
name: 'Sporting Goods',
items: [
{ name:...
Not so Loose Coupling, Not so High Reuse
● Parent needs to need NOT know about child’s data
○ Need to fetch data for child...
RelayJS: What it Brings to GraphQL
Why RelayJS?
● Usable features:
○ Component-Data Co-location
○ Connection Id: Data re-fetching
○ Connections: One-to-Many ...
RelayJS: Setup
RelayJS: Component-Data Co-location
Browser
GraphQL
/RelayJS
Server
Bundled
JSAny Server
JS Libraries
react
react-dom
reac...
References
● Articles
○ GraphQL/RelayJS (non NodeJS): https://medium.com/@khor/relay-facebook-on-rails-8b4af2057152
○ Pure...
Thank you:
● All for coming!
● Toru for invite!
● Facebook for tech & engineers!
Flux: The ‘pure’ version
Todo App
New Todo
Create
Todo #1
Todo #2
Created Todo List
Todo App: React with AJAX
Render
render() {
return (_.map(
this.state.todos,
(e) => { return <div>{e}</div> })
)
}
Get Tod...
Flux: Code Organization
Views
Actions
Get Todos
getTodot() {
$.ajax {
url: …GET
success: (data) => {
this.setState(data);
...
Flux: Data Flow
Views
Actions
Get Todos
getTodos() {
$.ajax {
url: …GET
success: (data) => {
this.setState(data);
}
}
}
Ad...
Get Todos
getTodot() {
$.ajax {
url: …GET
success: (data) => {
this.setState(data);
}
}
}
Add Todo
addToto() {
$.ajax {
ur...
Flux: Data Flow
Views
Actions
Views
Dispatcher
● Throttles one Action at a time
● waitsFor()
Todo Store
User Store
registe...
Flux: Data Flow
Views
Actions
Views
Dispatcher
● Throttles one Action at a time
● waitsFor()
Todo Store
User Store
listen
...
Flux
Courtesy: http://fluxxor.com/what-is-flux.html
Flux: Additional Slides
Todo App: React with props
Data
const _props = {
todos: [
‘Todo #1’, ‘Todo #2’
]
}
Code
render() {
return (_.map(
this.pro...
Todo App with Flux
Data
const _props = {
todos: [
‘Todo #1’, ‘Todo #2’
]
}
Code
render() {
return (_.map(
this.props.todos...
Action Creator Trigger
<form>
<input id=’todo-text’ type=’text’ />
<button onClick=TodoActions.create($(‘#todo-text’).val(...
Action Creator
TodoActions: {
create: function(text) {
// Take some action, e.g., call REST API
AppDispatcher.dispatch({
a...
Store
AppDispatcher.register(function(action) { // action is passed in by Action Creator
var event = action.event;
switch(...
Store (cont.)
var TodoStore = assign({}, EventEmitter.prototype, {
// EventEmitter provides emit, on, removeListener, etc....
Controller-View
// This is where React is used
var TodoApp = React.createClass({
componentDidMount: function() {
TodoStore...
Upcoming SlideShare
Loading in …5
×

Tokyo React.js #3: Missing Pages: ReactJS/Flux/GraphQL/RelayJS

4,058 views

Published on

Missing Pages: ReactJS/Flux/GraphQL/RelayJS. Shed light on assumptions/details glossed over by Facebook docs. Presented at Tokyo React.js Meetup #3 (http://reactjs-meetup.connpass.com/event/26229/)

Japanese version: https://www.slideshare.net/KhorSoonHin/reactjs-3-meetup-ja

Video: https://youtu.be/YFuQlKBXlmA

Published in: Technology
  • Dating direct: ♥♥♥ http://bit.ly/36cXjBY ♥♥♥
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Follow the link, new dating source: ❤❤❤ http://bit.ly/36cXjBY ❤❤❤
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Tokyo React.js #3: Missing Pages: ReactJS/Flux/GraphQL/RelayJS

  1. 1. Missing Pages: ReactJS/Flux/GraphQL/RelayJS Khor, @neth_6, re:Culture
  2. 2. Shed light on assumptions/details glossed over in FB’s docs
  3. 3. Agenda ● Using pure Flux ● GraphQL ○ Sans RelayJS ○ Setup GraphQL on non-NodeJS servers ● RelayJS ○ Revisiting ReactJS: Reduce coupling, increase reusability ○ What RelayJS Brings to GraphQL ○ Setup RelayJS/GraphQL on non-NodeJS servers
  4. 4. React Family: In a Few Words ... ● ReactJS: UI data & rendering ● Flux: Data flow & code organization ● GraphQL: Single API endpoint data retrieval ● RelayJS: React component data declaration & co-location
  5. 5. GraphQL: Sans RelayJS
  6. 6. GraphQL I speak GraphQL API Endpoint Single Endpoint can Deliver all data store(email: “admin@abc.com”) { name: ‘Hello Shop’, address: ‘1-3-1 Aoyama’ categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price: 20, stock: 50 }, { name: ‘Baseball’, price: 5, stock: 30 }, … ], ... }, … ], }
  7. 7. GraphQL (cont.) API Endpoint query { store(email: "admin@abc.com") { name, address } }
  8. 8. GraphQL (cont.) API Endpoint query { store(email: "admin@abc.com") { name, address } } store(email: “admin@abc.com”) { name: ‘Hello Shop’, address: ‘1-3-1 Aoyama’ } Welcome to Hello Shop Visit us at 1-3-1 Aoyama Or shop online
  9. 9. GraphQL (cont.) API Endpoint query { store(email: "admin@abc.com") { categories { name, products { name, price, stock } } } } store { categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price:, stock: 50 }, … }, ... ] } Hello Shop
  10. 10. GraphQL (cont.) API Endpoint query { store(email: "admin@abc.com") { categories { name, products { name, price, stock } } } } store { categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price:, stock: 50 }, … }, ... ] } Single endpoint Hierarchical data query Client-specified query Data in 1 round-trip
  11. 11. GraphQL: Setup
  12. 12. GraphQL: Like all Client-Server Browser http(s) Any Server
  13. 13. GraphQL: Over HTTP(S) Browser GraphQL Server Bundled JS GraphQL over http(s), etc. Any Server
  14. 14. GraphQL Over http(s) GraphQL over http
  15. 15. GraphQL: Enabling the Server Browser GraphQL Server Bundled JS GraphQL over http(s), etc. Any Server Server Libraries graphql GraphQL Schema in Hash
  16. 16. GraphQL: JS Code Browser GraphQL Server Bundled JS Bundled JS Any Server GraphQL over http(s), etc. Server Libraries graphql GraphQL Schema in Hash
  17. 17. GraphQL: Required JS Libraries Browser GraphQL Server Bundled JS Bundled JS Any Server JS Libraries react react-dom graphql GraphQL over http(s), etc. Server Libraries graphql GraphQL Schema in Hash
  18. 18. GraphQL: Bundling Your JS Code Browser GraphQL Server Bundled JS Bundled JS Any Server JS Libraries react react-dom graphql GraphQL over http(s), etc. Server Libraries graphql Your JS browserify/w ebpackGraphQL Schema in Hash
  19. 19. ReactJS (Review)
  20. 20. ReactJS ● Single-Page Application (SPA) Courtesy: https://facebook.github.io/react/docs/thinking-in-react.html Hello Shop
  21. 21. ReactJS (cont.) ● Single-Page Application (SPA) ● Cascading Views Hello Shop
  22. 22. ReactJS (cont.) ● Single-Page Application (SPA) ● Cascading Views Hello Shop
  23. 23. React (cont.) ● Single-Page Application (SPA) ● Cascading Views Hello Shop Hierarchical Views => GraphQL Hierarchical Data
  24. 24. ReactJS (cont.) Abstraction Each ReactJS element knows: ● The data it needs ● How to render itself with HTML fragments ● The data it passes to its children
  25. 25. React (cont.) ● Single-Page Application (SPA) ● Cascading Views Fetch Data Hello Shop
  26. 26. React (cont.) ● Single-Page Application (SPA) ● Cascading Views Hello Shop
  27. 27. React (cont.) ● Single-Page Application (SPA) ● Cascading Views Hello Shop
  28. 28. Passing Data to Children this.props = { store: name: ‘Hello Shop’ categories: [ { name: 'Sporting Goods', items: [ { name: 'Football', price: … } … ], }, ... ], }, } Use Data & Render this.props.store.name Pass Down this.props.store.categories
  29. 29. Not so Loose Coupling, Not so High Reuse ● Parent needs to know about child’s data ○ Need to fetch data for children ○ Need to pass correct data to children render() { return ( <Store>{this.props.store} /> <Categories categories={this.props.store.categories} /> ) }
  30. 30. RelayJS: Component-Data Co-location Reduce coupling, increase reusability
  31. 31. GraphQL I speak GraphQL API Endpoint Single Endpoint can Deliver all data store(email: “admin@abc.com”) { name: ‘Hello Shop’, address: ‘1-3-1 Aoyama’ categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price: 20, stock: 50 }, { name: ‘Baseball’, price: 5, stock: 30 }, … ], ... }, … ], }
  32. 32. Sample App: Refresh your Memory Hello Shop
  33. 33. Sample App: Simplified Hello Shop
  34. 34. RelayJS: Component & Data Co-location store(email: “admin@abc.com”) { name: ‘Hello Shop’, address: ‘1-3-1 Aoyama’ categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price: 20, stock: 50 }, { name: ‘Baseball’, price: 5, stock: 30 }, … ], ... }, … ], } fragment on Store { name, address } Hello Shop
  35. 35. store(email: “admin@abc.com”) { name: ‘Hello Shop’, address: ‘1-3-1 Aoyama’ categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price: 20, stock: 50 }, { name: ‘Baseball’, price: 5, stock: 30 }, … ], ... }, … ], } fragment on Store { categories { name, products, } } RelayJS: Component & Data Co-location
  36. 36. store(email: “admin@abc.com”) { name: ‘Hello Shop’, address: ‘1-3-1 Aoyama’ categories: [ { name: ‘Sporting Goods’, products: [ { name: ‘Football’, price: 20, stock: 50 }, { name: ‘Baseball’, price: 5, stock: 30 }, … ], ... }, … ], } Hello Shop RelayJS will fetch UNION of data
  37. 37. Passing Data to Children this.props = { store: name: ‘Hello Shop’ categories: [ { name: 'Sporting Goods', items: [ { name: 'Football', price: … } … ], }, ... ], }, } Use Data & Render this.props.store.name Pass Down this.props.store.categories
  38. 38. Not so Loose Coupling, Not so High Reuse ● Parent needs to need NOT know about child’s data ○ Need to fetch data for children ○ Need to pass correct data to children render() { return ( <Store>{this.props.store} /> <Categories categories={this.props.store.categories} /> ) }
  39. 39. RelayJS: What it Brings to GraphQL
  40. 40. Why RelayJS? ● Usable features: ○ Component-Data Co-location ○ Connection Id: Data re-fetching ○ Connections: One-to-Many Relationships/Pagination ○ Mutations: Modified data auto-updates affected React components ● Implicit features: ○ Auto-fetch declared data (no AJAX code) ○ Caching, batching data ● Bells & Whistles: ○ Show spinner, etc. during loading ○ Show error message, etc., if data fetch fail ○ Optimistic UI updates
  41. 41. RelayJS: Setup
  42. 42. RelayJS: Component-Data Co-location Browser GraphQL /RelayJS Server Bundled JSAny Server JS Libraries react react-dom react-relay babelify-relay- plugin babelify RelayJS containers calling GraphQL over http(s), etc. graphql Server Libraries graphql Your JS with Relay.QL browserify/w ebpack GraphQL Schema in JSON Bundled JS GraphQL Schema in Hash Converter graphql-relay
  43. 43. References ● Articles ○ GraphQL/RelayJS (non NodeJS): https://medium.com/@khor/relay-facebook-on-rails-8b4af2057152 ○ Pure ‘Flux’ (non NodeJS): https://medium.com/@khor/back-to-front-rails-to-facebook-s-flux-ae815f81b16c ● Starter-kit ○ Rails: https://github.com/nethsix/relay-on-rails ● Choices: React, React (with Container), Flux/Redux, GraphQL/RelayJS ○ Shared by @koba04 - http://andrewhfarmer.com/react-ajax-best-practices/ ● Follow: @neth_6, @reculture_us
  44. 44. Thank you: ● All for coming! ● Toru for invite! ● Facebook for tech & engineers!
  45. 45. Flux: The ‘pure’ version
  46. 46. Todo App New Todo Create Todo #1 Todo #2 Created Todo List
  47. 47. Todo App: React with AJAX Render render() { return (_.map( this.state.todos, (e) => { return <div>{e}</div> }) ) } Get Todos componentDidMount() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add Todo onAddTodo() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit Todo onEditTodo() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } } . . . Data this.setState = { todos: [ ‘Todo #1’, ‘Todo #2’ ] }
  48. 48. Flux: Code Organization Views Actions Get Todos getTodot() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add Todo addToto() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit Todo editTodo() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } } this.setState = { todos: [ ‘Todo #1’, ‘Todo #2’ ] }
  49. 49. Flux: Data Flow Views Actions Get Todos getTodos() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add Todo addTodo() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit Todo editTodo() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } } this.setState = { todos: [ ‘Todo #1’, ‘Todo #2’ ] } Dispatcher ● Throttles one Action at a time ● waitsFor()
  50. 50. Get Todos getTodot() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add Todo addToto() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit Todo editTodo() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } } Flux: Data Flow Views this.setState = { todos: [ ‘Todo #1’, ‘Todo #2’ ] users: [ ‘User #1, ‘User #2’ ] } Actions Views Get Users getUsers() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add User addUser() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit User editUser() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } } Dispatcher ● Throttles one Action at a time ● waitsFor()
  51. 51. Flux: Data Flow Views Actions Views Dispatcher ● Throttles one Action at a time ● waitsFor() Todo Store User Store register this.setState = { todos: [ ‘Todo #1’, ‘Todo #2’ ] } this.setState = { users: [ ‘User #1, ‘User #2’ ] } register Get Todos getTodot() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add Todo addToto() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit Todo editTodo() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } } Get Users getUsers() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add User addUser() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit User editUser() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } }
  52. 52. Flux: Data Flow Views Actions Views Dispatcher ● Throttles one Action at a time ● waitsFor() Todo Store User Store listen this.setState = { todos: [ ‘Todo #1’, ‘Todo #2’ ] } this.setState = { users: [ ‘User #1, ‘User #2’ ] } listen listen Todo Actions listen User Actions Get Todos getTodot() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add Todo addToto() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit Todo editTodo() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } } Get Users getUsers() { $.ajax { url: …GET success: (data) => { this.setState(data); } } } Add User addUser() { $.ajax { url: …POST success: (data) => { this.setState(data); } } } Edit User editUser() { $.ajax { url: …PUT success: (data) => { this.setState(data); } } }
  53. 53. Flux Courtesy: http://fluxxor.com/what-is-flux.html
  54. 54. Flux: Additional Slides
  55. 55. Todo App: React with props Data const _props = { todos: [ ‘Todo #1’, ‘Todo #2’ ] } Code render() { return (_.map( this.props.todos, (e) => { return <div>{e}</div> }) ) } Initialize const _root = document.findElementById(‘root’); ReactDOM.render(<TodoApp {..._props} />, _root);
  56. 56. Todo App with Flux Data const _props = { todos: [ ‘Todo #1’, ‘Todo #2’ ] } Code render() { return (_.map( this.props.todos, (e) => { return <div>{e}</div> }) ) } Initialize const _root = document.findElementById(‘root’); ReactDOM.render(<TodoApp {..._props} />, _root);
  57. 57. Action Creator Trigger <form> <input id=’todo-text’ type=’text’ /> <button onClick=TodoActions.create($(‘#todo-text’).val())>Create</button> </form>
  58. 58. Action Creator TodoActions: { create: function(text) { // Take some action, e.g., call REST API AppDispatcher.dispatch({ actionType: TodoConstants.TODO_CREATE, // Basically ‘create’ text: text }); }, …. }
  59. 59. 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
  60. 60. 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
  61. 61. 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

×