Introduction to React and Flux (CodeLabs)

40
React + Flux Eueung Mulyana http://eueung.github.io/js/react JS CodeLabs | Attribution-ShareAlike CC BY-SA 1 / 40

Transcript of Introduction to React and Flux (CodeLabs)

React + FluxEueung Mulyana

http://eueung.github.io/js/reactJS CodeLabs | Attribution-ShareAlike CC BY-SA

1 / 40

Agenda

React Basics #1

React Basics #2

Flux

2 / 40

React Basics #1A JavaScript library for building UIs | React

3 / 40

<!DOCTYPE html><html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> <script src="react-0.14.5/react.js"></script> <script src="react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js" </head> <body> <div id="example"></div> <script type="text/babel"> ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') ); </script> </body></html>

Render @Browserhello-00-A.html

4 / 40

Render @Browserhello-01-B.html

src/hello-01.js

ReactDOM.render( document.getElementById('example'));

<!DOCTYPE html><html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> <script src="react-0.14.5/react.js"></script> <script src="react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js" </head> <body> <div id="example"></div> <script type="text/babel" src="src/hello-01.js"></script </body></html>

<h1>Hello, world!</h1>,

5 / 40

<!DOCTYPE html><html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> <script src="react-0.14.5/react.js"></script> <script src="react-0.14.5/react-dom.js"></script> </head> <body> <div id="example"></div> <script src="build/hello-02.js"></script> </body></html>

# src/hello-02.js (JSX)ReactDOM.render( document.getElementById('example'));

# build/hello-02.js (compiled)ReactDOM.render(React.createElement( 'h1', null, 'Hello, world!'), document.getElementById('example'));

<h1>Hello, world!</h1>,

PrecompileJSX to vanilla JS

npm install -g babel-cli npm install -g babel-preset-react npm install -g babel-preset-es2015

$> babel --presets react hello-02.js --out-dir=../buildhello-02.js -> ..\build\hello-02.js

6 / 40

this.props 

hello-03.js

<!DOCTYPE html><html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> <script src="react-0.14.5/react.js"></script> <script src="react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js" </head> <body> <div id="example"></div> <script type="text/babel" src="src/hello-03.js"></script </body></html>

var HelloMessage = React.createClass({ render: function() { return }});

ReactDOM.render(

<div>Hello {this.props.name}</div>;

<HelloMessage name="John" />, document.getElementById('example'));

7 / 40

hello-04.js

var Timer = React.createClass({ getInitialState: function() { return {secondsElapsed: 0}; }, tick: function() { this.setState({secondsElapsed: this.state.secondsElapsed + }, componentDidMount: function() { this.interval = setInterval(this.tick, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: function() { return ( ); }});

ReactDOM.render(

<div>Seconds Elapsed: {this.state.secondsElapsed}</div

<Timer />, document.getElementById('example'));

this.state 

8 / 40

TodoApp

var TodoList = React.createClass({ render: function() { var createItem = function(item) { return }; return }});

hello-05.js

<li key={item.id}>{item.text}</li>;

<ul>{this.props.items.map(createItem)}</ul>;

var TodoApp = React.createClass({ getInitialState: function() { return {items: [], text: ''}; }, onChange: function(e) { this.setState({text: e.target.value}); }, handleSubmit: function(e) { e.preventDefault(); var nextItems = this.state.items.concat([{text: this.state.text, id: var nextText = ''; this.setState({items: nextItems, text: nextText}); }, render: function() { return ( <h3>TODO</h3> <TodoList items={this.state.items} /> <form onSubmit={this.handleSubmit}> <input onChange={this.onChange} value={this.state.text} <button>{'Add #' + (this.state.items.length + 1)} </form> </div> ); }});

ReactDOM.render(

<div>

<TodoApp />, document.getElementById('example'));

9 / 40

TodoApp | hello-05.js

10 / 40

hello-06.html

<!DOCTYPE html><html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> <script src="react-0.14.5/react.js"></script> <script src="react-0.14.5/react-dom.js"></script>

<script src="https://facebook.github.io/react/js/marked.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js" </head> <body> <div id="example"></div> <script type="text/babel" src="src/hello-06.js"></script </body></html>

MarkdownEditorA Component Using External Plugins 

11 / 40

hello-06.js

var MarkdownEditor = React.createClass({ getInitialState: function() { return {value: 'Type some *markdown* here!'}; }, handleChange: function() { this.setState({value: this.refs.textarea.value}); }, rawMarkup: function() { return { __html: marked(this.state.value, {sanitize: true }, render: function() { return ( <h3>Input</h3> <textarea onChange={this.handleChange} ref="textarea" defaultValue={this.state.value} /> <h3>Output</h3> <div className="content" dangerouslySetInnerHTML={this.rawMarkup()} /> </div> ); }});

ReactDOM.render(

<div className="MarkdownEditor">

<MarkdownEditor />, document.getElementById('example'));

12 / 40

React Basics #2Starter Kit Examples

13 / 40

<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>Basic Example</title> <link rel="stylesheet" href="../shared/css/base.css" /> </head> <body> <h1>Basic Example</h1>

<div id="container"> <p> To install React, follow the instructions on <a href <p> If you can see this, React is not working right. If you checked out the source from GitHub make sure to run </div>

<h4>Example Details</h4> <p>This is written in vanilla JavaScript (without JSX) and transformed in the browser. <p> Learn more about React at <a href="https://facebook.github.io/react"

<script src="../../react-0.14.5/react.js"></script> <script src="../../react-0.14.5/react-dom.js"></script> <script> ... </script> </body></html>

Example #1React with Vanilla JS

<script> var ExampleApplication = React.createClass({ render: function() { var elapsed = Math.round(this.props.elapsed / 100); var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' var message = 'React has been successfully running for ' + seconds +

return React.DOM.p(null, message); } });

// Call React.createFactory instead of directly call ExampleApplication({...}) in React.render var ExampleApplicationFactory = React.createFactory(ExampleApplication);

var start = new Date().getTime(); setInterval(function() { ReactDOM.render( ExampleApplicationFactory({elapsed: new Date().getTime() - start}), document.getElementById('container') ); }, 50);</script>

14 / 40

Example #2React with JSX

<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>Basic Example with JSX</title> <link rel="stylesheet" href="../shared/css/base.css" /> </head> <body> <h1>Basic Example with JSX</h1> <div id="container"> <p> To install React, follow the instructions on <a href <p> If you can see this, React is not working right. If you checked out the source from GitHub make sure to run </div>

<h4>Example Details</h4> <p>This is written with JSX and transformed in the browser. <p>Learn more about React at <a href="https://facebook.github.io/react"

<script src="../../react-0.14.5/react.js"></script> <script src="../../react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"

<script type="text/babel"> ... </script> </body></html>

<script type="text/babel"> var ExampleApplication = React.createClass({ render: function() { var elapsed = Math.round(this.props.elapsed / 100); var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' var message = 'React has been successfully running for ' + seconds +

return } }); var start = new Date().getTime(); setInterval(function() { ReactDOM.render( document.getElementById('container') ); }, 50);</script>

<p>{message}</p>;

<ExampleApplication elapsed={new Date().getTime() - start

15 / 40

Example #1 

Example #2 

16 / 40

Example #3Basic Click Counter (JSX)

 

<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>Basic Example with Click Counter</title> <script src="../../react-0.14.5/react.js"></script> <script src="../../react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js" </head> <body> <div id="message" align="center"></div>

<script type="text/babel"> var Counter = React.createClass({ getInitialState: function () { return { clickCount: 0 }; }, handleClick: function () { this.setState(function(state) { return {clickCount: state.clickCount + 1}; }); }, render: function () { return (<h2 onClick={this.handleClick}>Click me! Number of clicks: {this.state.clickCount} } }); ReactDOM.render( <Counter />, document.getElementById('message') ); </script></body></html>

17 / 40

<!DOCTYPE html><html> <head> ... </head>

<body> ...

<script src="../../react-0.14.5/react.js"></script> <script src="../../react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js" <script type="text/babel" src="example.js"></script> </body></html>

Example #4External JSX

 

example.js

var ExampleApplication = React.createClass({ render: function() { var elapsed = Math.round(this.props.elapsed / 100); var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' ); var message = 'React has been successfully running for '

return }});

var start = new Date().getTime();

setInterval(function() { ReactDOM.render( }, 50);

<p>{message}</p>;

<ExampleApplication elapsed={new Date().getTime

18 / 40

Example #5Precompiled JSX (Vanilla JS @Browser)

 

$> babel --presets react example.js --out-dir=buildexample.js -> build\example.js

<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>Basic Example with Precompiled JSX</title> <link rel="stylesheet" href="../shared/css/base.css" /> </head> <body> <h1>Basic Example with Precompiled JSX</h1> <div id="container"> <p> If you can see this, React is not running. Try running: <pre> ... </pre> </div>

<h4>Example Details</h4> <p>This is written with JSX in a separate file and precompiled to vanilla JS by running: <pre> npm install -g babel cd examples/basic-jsx-precompile/ babel example.js --out-dir=build </pre> <p> Learn more about React at <a href="https://facebook.github.io/react"

<script src="../../react-0.14.5/react.js"></script> <script src="../../react-0.14.5/react-dom.js"></script> <script src="build/example.js"></script> </body></html>

19 / 40

Example #6JSX and Harmony (ES6|ES2015)

<!DOCTYPE html>

<head> <meta charset="utf-8"> <title>Basic Example with JSX and ES6 features</title> <link rel="stylesheet" href="../shared/css/base.css" /> </head> <body> <h1>Basic Example with JSX and ES6 features</h1> <div id="container"> <p>To install React, follow the instructions on <a href <p> If you can see this, React is not working right. If you checked out the source from GitHub make sure to run </div>

<h4>Example Details</h4> <p>This is written with JSX with Harmony (ES6) syntax and transformed in the browser. <p>Learn more about React at <a href="https://facebook.github.io/react"

<script src="../../react-0.14.5/react.js"></script> <script src="../../react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js" <script type="text/babel"> ... </script> </body></html>

<html>

<script type="text/babel"> class ExampleApplication extends React.Component { render() { var elapsed = Math.round(this.props.elapsed / 100); var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' var message = ̀React has been successfully running for

return } } var start = new Date().getTime(); setInterval(() => { ReactDOM.render( }, 50);</script>

<p>{message}</p>;

<ExampleApplication elapsed={new Date()

20 / 40

Example #7CommonJS & Browserify (Bundled Vanilla JS @ Browser)

package.json

{ "name": "react-basic-commonjs-example", "description": "Basic example of using React with CommonJS" "main": "index.js", "dependencies": { "babelify": "̂6.3.0", "react": "̂0.14.0-rc1", "react-dom": "̂0.14.0-rc1", "watchify": "̂3.4.0" }, "scripts": { "start": "watchify index.js -v -t babelify -o bundle.js" }} npm install

npm start

21 / 40

index.js

'use strict';

var React = require('react');var ReactDOM = require('react-dom');

var ExampleApplication = React.createClass({ render: function() { var elapsed = Math.round(this.props.elapsed / 100); var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' ); var message = 'React has been successfully running for ' + seconds +

return }});

var start = new Date().getTime();

setInterval(function() { ReactDOM.render( document.getElementById('container') );}, 50);

<p>{message}</p>;

<ExampleApplication elapsed={new Date().getTime() - start

index.html

<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>Basic CommonJS Example with Browserify</title> <link rel="stylesheet" href="../shared/css/base.css" /> </head> <body> <h1>Basic CommonJS Example with Browserify</h1> <div id="container"> <p>To install React, follow the instructions on <a href <p>If you can see this, React is not working right. If you checked out the source from GitHub make sure to run </div>

<h4>Example Details</h4> <p>This is written with JSX in a CommonJS module and precompiled to vanilla JS by running: <pre>npm start</pre> <p>Learn more about React at <a href="https://facebook.github.io/react"

<script src="bundle.js"></script> </body></html>

22 / 40

Example #8 

index.html

<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>Quadratic Formula Calculator</title> <link rel="stylesheet" href="../shared/css/base.css" /> </head> <body> <h1>Quadratic Formula Calculator</h1> <div id="container"> <p>If you can see this, React is not working right. This is probably because you're viewing this on your file system instead of a web server. Try running </div>

<h4>Example Details</h4> <p>This is written with JSX in a separate file and transformed in the browser. <p>Learn more about React at <a href="https://facebook.github.io/react"

<script src="../../react-0.14.5/react.js"></script> <script src="../../react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js" <script type="text/babel" src="example.js"></script> </body></html>

23 / 40

var QuadraticCalculator = React.createClass({ getInitialState: function() { return { a: 1, b: 3, c: -4 }; },

handleInputChange: function(key, event) { var partialState = {}; partialState[key] = parseFloat(event.target.value); this.setState(partialState); },

render: function() { var a = this.state.a; var b = this.state.b; var c = this.state.c; var root = Math.sqrt(Math.pow(b, 2) - 4 * a * c); var denominator = 2 * a; var x1 = (-b + root) / denominator; var x2 = (-b - root) / denominator; return ( <strong> <em>ax</em><sup>2</sup> + <em>bx</em> + <em>c</em> = 0 </strong> <h4>Solve for <em>x</em>:</h4> <p> <label> a: <input type="number" value={a} onChange={this.handleInputChange.bind(null, <label> b: <input type="number" value={b} onChange={this.handleInputChange.bind(null, <label> c: <input type="number" value={c} onChange={this.handleInputChange.bind(null, x: <strong>{x1}, {x2}</strong> </p> </div> ); }});

ReactDOM.render(

<div>

<QuadraticCalculator />, document.getElementById('container') );

example.js

24 / 40

Example #9WebComponents

25 / 40

<!DOCTYPE html>

<head> <meta http-equiv='Content-type' content='text/html; charset=utf-8' <title>Basic Example with WebComponents</title> <link rel="stylesheet" href="../shared/css/base.css" /> </head> <body> <h1>Basic Example with WebComponents</h1> <div id="container"> <p>To install React, follow the instructions on <a href <p>If you can see this, React is not working right. If you checked out the source from GitHub make sure to run </div><br /><br />

<h4>Example Details</h4> <p>This example demonstrates WebComponent/ReactComponent interoperability by rendering a ReactComponent, which renders a WebComponent, which renders another ReactComponent in the WebComponent's shadow DOM. <p>Learn more about React at <a href="http://facebook.github.io/react"

<script src="../shared/thirdparty/webcomponents.js"></script <script src="../../react-0.14.5/react.js"></script> <script src="../../react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"

<script type="text/babel"> ... </script> </body></html>

<html>

index.html

<script type="text/babel"> var proto = Object.create(HTMLElement.prototype, { createdCallback: { value: function() { var mountPoint = document.createElement('span'); this.createShadowRoot().appendChild(mountPoint);

var name = this.getAttribute('name'); var url = 'https://www.google.com/search?q=' + encodeURIComponent ReactDOM.render( } } }); document.registerElement('x-search', {prototype: proto});

class HelloMessage extends React.Component { render() { return <div>Hello <x-search name={this.props.name} />! } }

// Mount React Component (which uses WebComponent which uses React) var container = document.getElementById('container'); ReactDOM.render(</script>

<a href={url}>{name}</a>, mountPoint);

<HelloMessage name="Jim Sproch" />, container);

26 / 40

Example #10 

<div id="container"><span class="animateExample" data-reactid=".0"> <div class="animateItem" style="left: 0px; background: red;" <div class="animateItem" style="left: 128px; background: gray;" <div class="animateItem" style="left:256px;background:blue;"</span></div>

27 / 40

index.html

<!DOCTYPE html>

<head> <meta charset="utf-8"> <title>Example with Transitions</title> <link rel="stylesheet" href="../shared/css/base.css" /> <link rel="stylesheet" href="transition.css" /> </head> <body> <h1>Example with Transitions</h1> <div id="container"> <p>To install React, follow the instructions on <a href <p>If you can see this, React is not working right. If you checked out the source from GitHub make sure to run </div>

<h4>Example Details</h4> <p>This is written with JSX and transformed in the browser. <p>Learn more about React at <a href="https://facebook.github.io/react"

<script src="../../react-0.14.5/react-with-addons.js"></ <script src="../../react-0.14.5/react-dom.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js"

<script type="text/babel"> ... </script> </body></html>

<html>

<script type="text/babel"> var CSSTransitionGroup = React.addons.CSSTransitionGroup; var INTERVAL = 2000;

var AnimateDemo = React.createClass({ getInitialState: function() { return {current: 0}; }, componentDidMount: function() { this.interval = setInterval( componentWillUnmount: function() { clearInterval(this.interval); }, tick: function() { this.setState({current: this.state.current +

render: function() { var children = []; var pos = 0; var colors = ['red', 'gray', 'blue']; for (var i = this.state.current; i < this.state.current + colors.length; i++) { var style = { left: pos * 128, background: colors[i % colors.length] }; pos++; children.push( } return ( {children} </CSSTransitionGroup> ); } });

ReactDOM.render(</script>

<div key={i} className="animateItem" style

<CSSTransitionGroup className="animateExample" transitionEnterTimeout

<AnimateDemo />, document.getElementById('container'));

28 / 40

transition.css

.example-enter,

.example-leave { -webkit-transition: all .25s; transition: all .25s;}

.example-enter,

.example-leave.example-leave-active { opacity: 0.01;}

.example-leave.example-leave-active { margin-left: -128px;}

.example-enter { margin-left: 128px;}

.example-enter.example-enter-active,

.example-leave { margin-left: 0; opacity: 1;}

.animateExample { display: block; height: 128px; position: relative; width: 384px;}

.animateItem { color: white; font-size: 36px; font-weight: bold; height: 128px; line-height: 128px; position: absolute; text-align: center; -webkit-transition: all .25s; /* TODO: make this a move animation */ transition: all .25s; /* TODO: make this a move animation */ width: 128px;}

29 / 40

Structureapp.jsstores/ListStore.jsdispatcher/AppDispatcher.jscomponents/

AppRoot.jsxNewItemForm.jsx

31 / 40

32 / 40

{ ..., "dependencies": { "babelify": "̂7.2.0", "babel-preset-react": "̂6.3.13", "babel-preset-es2015": "̂6.3.13", "browserify": "̂12.0.1", "events": "̂1.1.0", "flux": "̂2.1.1", "gulp": "̂3.9.0", "gulp-rename": "̂1.2.1", "gulp-uglify": "̂1.5.1", "lodash": "̂3.10.1", "react": "̂0.14.5", "react-dom": "̂0.14.5", "run-sequence": "̂1.1.5", "vinyl-source-stream": "̂1.1.0" }, "devDependencies": {}, ...}

npm install -g react react-dom babelify browserify flux lodash eventsnpm install -g babel-preset-react babel-preset-es2015npm install -g vinyl-source-stream gulp gulp-uglify gulp-rename run-sequence

package.json

33 / 40

var gulp = require('gulp');var browserify = require('browserify');var babelify = require('babelify');var source = require('vinyl-source-stream');var uglify = require('gulp-uglify');var rename = require('gulp-rename');var runSequence = require('run-sequence');

gulp.task('build', function () { return browserify({ entries: 'app.js', extensions: ['.jsx'], debug: true }) .transform(babelify, {presets: ['es2015','react']}) .bundle() .pipe(source('bundle.js')) .pipe(gulp.dest('dist'));});

gulp.task('compress', function() { return gulp.src('./dist/bundle.js') .pipe(uglify()) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('dist'));});

gulp.task('default', function(cb) { runSequence('build','compress', cb);});

gulpfile.jsgulp.task('watch', function () { gulp.watch("./*.js", ['default']); gulp.watch("./components/*.jsx", ['default']); gulp.watch("./dispatcher/*.js", ['default']); gulp.watch("./stores/*.js", ['default']);});

34 / 40

index.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Easy Flux Example</title></head><body> <h1>Easy Flux Example</h1> <div id="app-root"></div> <script src="dist/bundle.min.js"></script></body></html>

$> gulp[09:25:53] Using gulpfile ./gulpfile.js[09:25:53] Starting 'default'...[09:25:53] Starting 'build'...[09:25:59] Finished 'build' after 5.48 s[09:25:59] Starting 'compress'...[09:26:04] Finished 'compress' after 4.99 s[09:26:04] Finished 'default' after 10 s

app.jsimport React from 'react';import ReactDOM from 'react-dom';import AppRoot from './components/AppRoot';

ReactDOM.render(<AppRoot />, document.getElementById('app-root'));

35 / 40

ListStore.js

import {EventEmitter} from 'events';import _ from 'lodash';//-----------------------------------let ListStore = _.extend({}, EventEmitter.prototype, { items: [ { name: 'Item 1', id: 0 }, { name: 'Item 2', id:

getItems: function(){ return this.items; }, addItem: function(new_item){ this.items.push(new_item); },

removeItem: function(item_id){ let items = this.items; _.remove(items,(item) => { return item_id == item.id; }); this.items = items; },

emitChange: function(){ this.emit('change'); }, addChangeListener: function(callback){ this.on('change', callback); }, removeChangeListener: function(callback) { this.removeListener(});//-----------------------------------export default ListStore;

AppDispatcher.js

import {Dispatcher} from 'flux';import ListStore from '../stores/ListStore';//-----------------------------------let AppDispatcher = new Dispatcher();//-----------------------------------AppDispatcher.register((payload) => { let action = payload.action; let new_item = payload.new_item; let id = payload.id;

switch(action) { case 'add-item': ListStore.addItem(new_item); break; case 'remove-item': ListStore.removeItem(id); break; default: return true; }

ListStore.emitChange(); return true;});//-----------------------------------export default AppDispatcher;

36 / 40

import React from 'react';import ListStore from '../stores/ListStore';import AppDispatcher from '../dispatcher/AppDispatcher';import NewItemForm from './NewItemForm';//-----------------------------------let getListState = () => { return { items: ListStore.getItems() }; }//-----------------------------------class AppRoot extends React.Component { constructor() { super(); this.state = getListState(); } _onChange() { this.setState(getListState()); }

componentDidMount() { ListStore.addChangeListener(this._onChange.bind(this)); } componentWillUnmount() { ListStore.removeChangeListener(this._onChange.bind(this)); }

removeItem(e){ let id = e.target.dataset.id; AppDispatcher.dispatch({ action: 'remove-item', id: id }); }

render(){ let _this = this; let items = ListStore.getItems(); let itemHtml = items.map(( listItem ) => { return }); return ( ; }}//-----------------------------------export default AppRoot;

<li key={ listItem.id }> { listItem.name } <button onClick={ _this.removeItem

<div> <ul> { itemHtml } </ul> <NewItemForm /> </div> )

AppRoot.jsx

37 / 40

NewItemForm.jsx

import React from 'react';import ReactDOM from 'react-dom';import AppDispatcher from '../dispatcher/AppDispatcher';//-----------------------------------class NewItemForm extends React.Component { createItem(e){ e.preventDefault(); let id = guid();

let item_title = ReactDOM.findDOMNode(this.refs.item_title).value.trim(); ReactDOM.findDOMNode(this.refs.item_title).value = '';

AppDispatcher.dispatch({ action: 'add-item', new_item: { id: id, name: item_title } }); }

render(){ return }}//-----------------------------------function guid() { function s4() { return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); } return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();}//-----------------------------------export default NewItemForm;

<form onSubmit={ this.createItem.bind(this) }> <input type="text" ref="item_title"

38 / 40

References1. A JavaScript library for building user interfaces | React2. Getting Started | React3. Building A Simple React Application Using The Flux Pattern: A Step-By-Step Guide4. flux/examples/flux-todomvc

39 / 40

ENDEueung Mulyana

http://eueung.github.io/js/reactJS CodeLabs | Attribution-ShareAlike CC BY-SA

40 / 40