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: Reduce coupling, increase reusability
○ What RelayJS Brings to GraphQL
○ Setup RelayJS/GraphQL on non-NodeJS servers
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
GraphQL: Sans RelayJS
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 },
…
],
...
}, …
],
}
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”) {
name: ‘Hello Shop’,
address: ‘1-3-1 Aoyama’
}
Welcome to Hello Shop
Visit us at 1-3-1 Aoyama
Or shop online
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
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
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
graphql
GraphQL
Schema
in Hash
GraphQL: JS Code
Browser
GraphQL
Server
Bundled
JS
Bundled
JS
Any Server
GraphQL
over
http(s), etc.
Server
Libraries
graphql
GraphQL
Schema
in Hash
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
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
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
● The data it passes to its children
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: 'Football', price: … }
…
],
},
...
],
},
}
Use Data & Render
this.props.store.name
Pass Down
this.props.store.categories
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} />
)
}
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 Shop’,
address: ‘1-3-1 Aoyama’
categories: [
{
name: ‘Sporting Goods’,
products: [
{ name: ‘Football’, price: 20, stock: 50 },
{ name: ‘Baseball’, price: 5, stock: 30 },
…
],
...
}, …
],
}
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’
categories: [
{
name: ‘Sporting Goods’,
products: [
{ name: ‘Football’, price: 20, stock: 50 },
{ name: ‘Baseball’, price: 5, stock: 30 },
…
],
...
}, …
],
}
fragment on Store {
name,
address
}
Hello Shop
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
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
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
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} />
)
}
RelayJS: What it Brings to GraphQL
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
RelayJS: Setup
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
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
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 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’
]
}
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’
]
}
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()
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()
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);
}
}
}
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);
}
}
}
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.props.todos,
(e) => { return <div>{e}</div> })
)
}
Initialize
const _root = document.findElementById(‘root’);
ReactDOM.render(<TodoApp {..._props} />, _root);
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);
Action Creator Trigger
<form>
<input id=’todo-text’ type=’text’ />
<button onClick=TodoActions.create($(‘#todo-text’).val())>Create</button>
</form>
Action Creator
TodoActions: {
create: function(text) {
// Take some action, e.g., call REST API
AppDispatcher.dispatch({
actionType: TodoConstants.TODO_CREATE, // Basically ‘create’
text: text
});
},
….
}
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
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
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

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

  • 1.
  • 2.
    Shed light onassumptions/details glossed over in FB’s docs
  • 3.
    Agenda ● Using pureFlux ● 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.
    React Family: Ina 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.
  • 6.
    GraphQL I speak GraphQL APIEndpoint 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.
    GraphQL (cont.) API Endpoint query{ store(email: "admin@abc.com") { name, address } }
  • 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.
    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.
    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.
  • 12.
    GraphQL: Like allClient-Server Browser http(s) Any Server
  • 13.
  • 14.
  • 15.
    GraphQL: Enabling theServer Browser GraphQL Server Bundled JS GraphQL over http(s), etc. Any Server Server Libraries graphql GraphQL Schema in Hash
  • 16.
    GraphQL: JS Code Browser GraphQL Server Bundled JS Bundled JS AnyServer GraphQL over http(s), etc. Server Libraries graphql GraphQL Schema in Hash
  • 17.
    GraphQL: Required JSLibraries 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.
    GraphQL: Bundling YourJS 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.
  • 20.
    ReactJS ● Single-Page Application(SPA) Courtesy: https://facebook.github.io/react/docs/thinking-in-react.html Hello Shop
  • 21.
    ReactJS (cont.) ● Single-PageApplication (SPA) ● Cascading Views Hello Shop
  • 22.
    ReactJS (cont.) ● Single-PageApplication (SPA) ● Cascading Views Hello Shop
  • 23.
    React (cont.) ● Single-PageApplication (SPA) ● Cascading Views Hello Shop Hierarchical Views => GraphQL Hierarchical Data
  • 24.
    ReactJS (cont.) Abstraction Each ReactJSelement knows: ● The data it needs ● How to render itself with HTML fragments ● The data it passes to its children
  • 25.
    React (cont.) ● Single-PageApplication (SPA) ● Cascading Views Fetch Data Hello Shop
  • 26.
    React (cont.) ● Single-PageApplication (SPA) ● Cascading Views Hello Shop
  • 27.
    React (cont.) ● Single-PageApplication (SPA) ● Cascading Views Hello Shop
  • 28.
    Passing Data toChildren 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.
    Not so LooseCoupling, 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.
    RelayJS: Component-Data Co-location Reducecoupling, increase reusability
  • 31.
    GraphQL I speak GraphQL APIEndpoint 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.
    Sample App: Refreshyour Memory Hello Shop
  • 33.
  • 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.
    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.
    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.
    Passing Data toChildren 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.
    Not so LooseCoupling, 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.
    RelayJS: What itBrings to GraphQL
  • 40.
    Why RelayJS? ● Usablefeatures: ○ 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.
  • 42.
    RelayJS: Component-Data Co-location Browser GraphQL /RelayJS Server Bundled JSAnyServer 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.
    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.
    Thank you: ● Allfor coming! ● Toru for invite! ● Facebook for tech & engineers!
  • 45.
  • 46.
    Todo App New Todo Create Todo#1 Todo #2 Created Todo List
  • 47.
    Todo App: Reactwith 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.
    Flux: Code Organization Views Actions GetTodos 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.
    Flux: Data Flow Views Actions GetTodos 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.
    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.
    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.
    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.
  • 54.
  • 55.
    Todo App: Reactwith 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.
    Todo App withFlux 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.
    Action Creator Trigger <form> <inputid=’todo-text’ type=’text’ /> <button onClick=TodoActions.create($(‘#todo-text’).val())>Create</button> </form>
  • 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.
    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.
    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.
    Controller-View // This iswhere 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