Slide 1

Slide 1 text

React and Flux @kevinold kevin@kevinold.com

Slide 2

Slide 2 text

React … is a JavaScript library for creating user interfaces

Slide 3

Slide 3 text

Why React? Simplify code Build Reusable Components Virtual DOM Build Isomorphic apps Eliminate querying / modifying DOM Small API / Easy to learn & remember

Slide 4

Slide 4 text

Building large applications with data that changes over time Simple Declarative

Slide 5

Slide 5 text

What we’ll cover JSX Components Props State Component Lifecycle App using only React App using React + Flux Tips

Slide 6

Slide 6 text

About the code snippets Written with JSX CommonJS syntax Packed with Browserify

Slide 7

Slide 7 text

JSX (Controversy)

Slide 8

Slide 8 text

HTML IN MY JS? // JSX React.render(

Hello, world!

, document.getElementById('example') ); // JavaScript React.render( // type, props, children React.createElement('h1', null, 'Hello, world!'), document.getElementById('example') );

Slide 9

Slide 9 text

Live JSX Compiler http://facebook.github.io/react/jsx-compiler.html

Slide 10

Slide 10 text

Components

Slide 11

Slide 11 text

Component Methods render() - required getInitialState() getDefaultProps()

Slide 12

Slide 12 text

render() var Div = React.createClass({ render: function() { return (
Hello World
); } }); // In other components (JSX)

Slide 13

Slide 13 text

getDefaultProps() var Div = React.createClass({ getDefaultProps: function() { return { name: 'Sir' }; }, render: function() { return (
Hello {this.props.name}
); } }); // In other components (JSX)

Slide 14

Slide 14 text

getInitialState() var Div = React.createClass({ getInitialState: function() { return getDataFromAPI(); }, render: function() { return (
Hello {this.state.name}
); } }); // In other components (JSX)

Slide 15

Slide 15 text

Additional Component Methods propTypes (object) mixins (array) statics (object)

Slide 16

Slide 16 text

Props // Contained in ReportList

Slide 17

Slide 17 text

State var Checkbox = React.createClass({ getInitialState: function() { return { isChecked: this.props.initialChecked || false }; }, _toggleCheckbox: function(){ this.setState({ isChecked: !this.state.isChecked }); },

Slide 18

Slide 18 text

Component Lifecycle

Slide 19

Slide 19 text

Component Lifecycle Mounting: componentWillMount() componentDidMount()* Updating: componentWillReceiveProps() shouldComponentUpdate()* componentWillUpdate() componentDidUpdate()* Unmounting: componentWillUnmount()

Slide 20

Slide 20 text

Reusable Components

Slide 21

Slide 21 text

Checkbox var Checkbox = React.createClass({ getInitialState: function() { return { isChecked: this.props.initialChecked || false }; }, _toggleCheckbox: function(){ this.setState({ isChecked: !this.state.isChecked }); },

Slide 22

Slide 22 text

Checkbox (cont.) render: function() { return (
{this.props.label}
); } });

Slide 23

Slide 23 text

Lists render:function(){ var items = []; _.each(this.state.expenseItems, function(expenseItem) { items.push(); }); return (
{items}
); }

Slide 24

Slide 24 text

Compose App of Components “Owns State” “Owns State” “Owns State”

Slide 25

Slide 25 text

Pure Component var Div = React.createClass({ render: function() { return (
Hello World
); } });

Slide 26

Slide 26 text

Component with State

Slide 27

Slide 27 text

var ExpenseRowForm = React.createClass({ getInitialState: function() { return { merchant: '' }; }, handleChange: function(event) { this.setState({ merchant: event.target.value }); }, render:function(){ var expense = this.props.expense; var formattedTotal = accounting.formatMoney(expense.total); return (
  • Save
  • ); } });

    Slide 28

    Slide 28 text

    Tips & Tricks

    Slide 29

    Slide 29 text

    Using jQuery inside components var Attachment = React.createClass({ componentDidMount: function() { var upload = jQuery(this.refs.fileInput.getDOMNode()); upload.uploadify({ // ... }); }, render: function() { return ( ); } });

    Slide 30

    Slide 30 text

    renderToString() var React = require('react/addons'); require('node-jsx').install(); var App = React.createFactory(require('./js/App.react')); // ... server.route({ method: 'GET', path: '/', handler: function (request, reply) { var reactHtml = React.renderToString(App({})); reply.view('index', { reactHtml: reactHtml }); } }); // Template
    {{ reactHtml }}

    Slide 31

    Slide 31 text

    React has great logs

    Slide 32

    Slide 32 text

    Recommendations CommonJS Browserify JSX npm install react npm install react-tools

    Slide 33

    Slide 33 text

    React Questions? (Flux is up next)

    Slide 34

    Slide 34 text

    Flux

    Slide 35

    Slide 35 text

    Simple Structure and Data Flow

    Slide 36

    Slide 36 text

    No content

    Slide 37

    Slide 37 text

    Actions

    Slide 38

    Slide 38 text

    var AppDispatcher = require('../dispatcher/AppDispatcher'); var AppConstants = require('../constants/AppConstants'); var ActionTypes = AppConstants.ActionTypes; module.exports = { clickReport: function(reportID) { AppDispatcher.handleViewAction({ type: ActionTypes.CLICK_REPORT, reportID: reportID }); } };

    Slide 39

    Slide 39 text

    Dispatcher

    Slide 40

    Slide 40 text

    var AppConstants = require('../constants/AppConstants'); var Dispatcher = require('flux').Dispatcher; var assign = require('object-assign'); var PayloadSources = AppConstants.PayloadSources; var AppDispatcher = assign(new Dispatcher(), { handleViewAction: function(action) { var payload = { source: PayloadSources.VIEW_ACTION, action: action }; this.dispatch(payload); } });

    Slide 41

    Slide 41 text

    var Dispatcher = require('flux').Dispatcher; module.exports = new Dispatcher(); /* * Copyright (c) 2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * AppDispatcher * * A singleton that operates as the central hub for application updates. */

    Slide 42

    Slide 42 text

    Store(s)

    Slide 43

    Slide 43 text

    var AppDispatcher = require('../dispatcher/AppDispatcher'); var AppConstants = require('../constants/AppConstants'); var EventEmitter = require('events').EventEmitter; var assign = require('object-assign'); var ActionTypes = AppConstants.ActionTypes; var CHANGE_EVENT = 'change'; var _currentID = 1; var _reports = [ { id: 1, title: "San Mateo Trip", start: "8/25", end:"8/29" }, { id: 2, title: "FL Trip", start: "4/2", end:"5/15" }, { id: 3, title: "Atlanta Trip", start: "1/12", end:"1/19" } ];

    Slide 44

    Slide 44 text

    var ExpenseReportStore = assign({}, EventEmitter.prototype, { emitChange: function() { this.emit(CHANGE_EVENT); }, addChangeListener: function(callback) { this.on(CHANGE_EVENT, callback); }, removeChangeListener: function(callback) { this.removeListener(CHANGE_EVENT, callback); },

    Slide 45

    Slide 45 text

    get: function(id){ return _reports[id]; }, getCurrentReport: function(){ return _reports[this.getCurrentID()]; }, getAll: function() { return _reports; }, getCurrentID: function(){ return _currentID; }, });

    Slide 46

    Slide 46 text

    ExpenseReportStore.dispatchToken = AppDispatcher.register(function(payload) { var action = payload.action; switch(action.type) { case ActionTypes.CLICK_REPORT: _currentID = action.reportID; ExpenseReportStore.emitChange(); break; default: // do nothing } });

    Slide 47

    Slide 47 text

    View (React)

    Slide 48

    Slide 48 text

    No content

    Slide 49

    Slide 49 text

    var React = require('react'); var cx = require('react/lib/cx'); var ExpenseReportStore = require('../stores/ ExpenseReportStore'); var ExpenseReportActions = require('../actions/ ExpenseReportActionCreators'); function getCurrentID() { return { currentID: ExpenseReportStore.getCurrentID() }; } var ExpenseReportRow = React.createClass({ getInitialState: function() { return getCurrentID(); },

    Slide 50

    Slide 50 text

    componentWillMount: function() { ExpenseReportStore.addChangeListener(this._onChange); }, componentUnWillMount: function() { ExpenseReportStore.removeChangeListener(this._onChange); }, _onChange: function() { this.setState(getCurrentID()); }, handleClick: function() { ExpenseReportActions.clickReport(this.props.expenseReport.id); },

    Slide 51

    Slide 51 text

    render:function(){ var grandTotal = generateGrandTotal(er); var classes = { 'list-group-item': true, 'active': this.state.currentID === this.props.expenseReport.id }; return (
  • {this.props.expenseReport.title}

    {grandTotal}
  • ) } });

    Slide 52

    Slide 52 text

    No content

    Slide 53

    Slide 53 text

    var ExpenseItemList = React.createClass({ getInitialState: function() { return getStateFromStores(); }, componentWillMount: function() { ExpenseReportStore.addChangeListener(this._onChange); ExpenseItemStore.addChangeListener(this._onChange); }, componentUnWillMount: function() { ExpenseReportStore.removeChangeListener(this._onChange); ExpenseItemStore.removeChangeListener(this._onChange); }, _onChange: function() { this.setState(getStateFromStores()); },

    Slide 54

    Slide 54 text

    render: function() { var state = this.state; var items = this.state.expenseItems.map(function(i) { if (state.currentExpenseItemID === i.id) { items.push(); } else { items.push(); } }); return (
    {items}
    ); } });

    Slide 55

    Slide 55 text

    Recommended App Flow

    Slide 56

    Slide 56 text

    No content

    Slide 57

    Slide 57 text

    React site - http://facebook.github.io/react/ Flux - http://facebook.github.io/flux/ Thinking in React - http://facebook.github.io/react/docs/thinking-in-react.html Egghead.io React Fundamentals - https://egghead.io/series/react-fundamentals Egghead.io Flux Architecture - https://egghead.io/series/react-flux-architecture “New” Dispatcher Example - https://github.com/facebook/flux/commit/ ec8bba6893da01dc0f4e7a136d47acfd2cea3ac4 Resources

    Slide 58

    Slide 58 text

    Thanks! Questions?