nyc react meetup - jun 2015
TRANSCRIPT
490 thousand
cloud clients
5 million
logins a day
19.5 thousand
logins a sec
35 million
active users
SaaS
We’re hiring
Developers / Engineers SDETs / QAs
Architects Scrum Masters
Solution Architects
Connecting data to UI (and back again)
• Where should data live
• Which component mutates (owns) state
• Decentralized or centralized (e.g. Om, Morearty, Baobab and others)
• Some data flow approaches
• Flux / CQRS / DDD (and which implementation?)
• RelayReferences http://facebook.github.io/react/docs/thinking-in-react.html https://github.com/enaqx/awesome-react#flux-implementations https://github.com/enaqx/awesome-react#relay https://github.com/uberVU/react-guide/blob/master/props-vs-state.md http://jaysoo.ca/2015/02/06/what-the-flux/
Flux overview• Different types of changes
• Initial data load
• User interaction
• Navigation and routing
• Interaction & sync with server
• Dependencies across stores and UI components (minimize & avoid reentrancy)
• Functional Reactive Programming (FRP) (more advanced)References https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
Baobab• Persistent and optionally immutable data tree with cursors
• Centralized model for application state
• Feature highlights
• Cursors, efficient mutations, events, flexible selection and traversal, facets, undo/redo and more
• Can be paired with React easily (baobab-react)
Create a tree and a cursorvar Baobab = require('baobab'); var stateTree = new Baobab({ admin: { users: [] }, home: { news: [] } }); !
var adminCursor = stateTree.select('admin'); var admin = adminCursor.get(); // { users: [] }
Listen to updates (on nested data)var notificationsCursor = adminCursor.select('notifications'); var feedsCursor = stateTree.select('home', 'feeds'); !adminCursor.on('update', function () { console.log('I saw a change'); // I will trigger }); !notificationsCursor.on('update', function () { console.log('I saw a change'); // I will trigger }); !feedsCursor.on('update', function () { console.log('I saw a change'); // Won’t trigger, on a different branch }); !notificationsCursor.push('foo');
Connect cursor(s) to a componentvar stateTree = require('./stateTree.js'); var React = require('react'); !var listCursor = stateTree.select('admin', 'notifications', 'list'); var MyComponent = React.createClass({ mixins: [listCursor.mixin], renderNotification: function (notification) { return ( <li>{notification.title}</li> ); }, render: function () { return ( <ul> {this.state.cursor.map(this.renderNotification)} </ul> ); } });
State changes
var Baobab = require('baobab'); var stateTree = new Baobab({ query: '', onlyProductsInStock: false, products: [] }); !module.exports = stateTree;
var stateTree = require('./stateTree'); var ajax = require('ajax'); module.exports = { showOnlyProductsInStock: function () { stateTree.set('onlyProductsInStock', true); }, showAllProducts: function () { stateTree.set('onlyProductsInStock', false); }, searchProducts: function (query) { stateTree.set('query', query); ajax.get('/products', query) .done(function (products) { stateTree.set('products', products); }); } };
stateTree.js
main.js
Optimizing renderingvar Baobab = require('baobab'); var ReactAddons = require('react/addons'); !
var stateTree = new Baobab({ notifications: [] }, { mixins: [ReactAddons.PureRenderMixin], shiftReferences: true }); !
module.exports = stateTree;
Undo / redovar baobab = new Baobab({colors: ['blue']}, {asynchronous: false}), cursor = baobab.select('colors'); !// Starting to record state, with 10 records maximum cursor.startRecording(10); !cursor.push('yellow'); cursor.push('purple'); cursor.push('orange'); !cursor.get(); >>> ['blue', 'yellow', 'purple', 'orange'] !cursor.undo(); cursor.get(); >>> ['blue', 'yellow', 'purple'] !cursor.undo(2); cursor.get(); >>> ['blue']
React integrationRoot Branchimport React, {Component} from 'react'; import Baobab from 'baobab'; import {root} from 'baobab-react/higher-order'; !var tree = new Baobab({ name: 'John', surname: 'Talbot' }); !class Application extends Component { render() { return ( <div> <OtherComponent /> </div> ); } } !var ComposedComponent = root(Application, tree); !React.render(<ComposedComponent />, mountNode);
import React, {Component} from 'react'; import {branch} from 'baobab-react/higher-order'; !class MyComponent extends Component { render() { ! // Cursor data is passed through props return ( <span> Hello {this.props.name} {this.props.surname} </span> ); } } !export default branch(MyComponent, { cursors: { name: ['name'], surname: ['surname'] } });
We’re hiring
Developers / Engineers SDETs / QAs
Architects Scrum Masters
Solution Architects
Thank you@tomrogers5
[email protected] https://linkedin.com/in/tomrogers3
Resources• https://github.com/tomrogers3/react-webgl-globe-viz
• https://www.youtube.com/watch?v=x7cQ3mrcKaY (highly recommended)
• http://facebook.github.io/react/docs/thinking-in-react.html
• https://github.com/enaqx/awesome-react
• https://github.com/Yomguithereal/baobab
• https://github.com/uberVU/react-guide/blob/master/props-vs-state.md
• http://jaysoo.ca/2015/02/06/what-the-flux/
• https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
• https://github.com/wiktor256/react-state-router