Slide 1

Slide 1 text

R E A C T. J S O N R A I L S

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

michael chan

Slide 4

Slide 4 text

@chantastic

Slide 5

Slide 5 text

@chantastic

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Launched 2006 on Rails 1.13

Slide 8

Slide 8 text

So our approach to JavaScript has been:

Slide 9

Slide 9 text

So our approach to JavaScript has been: Yes; write some

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

T U R B O L I N K S 3 . 0

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

B U T W E W E R E S T I L L W R I T I N G A L O T O F J AVA S C R I P T

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

C O M P O N E N T S

Slide 29

Slide 29 text

M Y G O A L

Slide 30

Slide 30 text

MY GOAL T H AT Y O U C O U L D S H I P A R E A C T C O M P O N E N T I N A N H O U R

Slide 31

Slide 31 text

STRETCH GOAL Y O U D O N ’ T M A K E T H E S A M E D U M B M I S TA K E S W E D I D

Slide 32

Slide 32 text

A R E A C T P R I M E R

Slide 33

Slide 33 text

J AVA S C R I P T L I B R A RY B Y FA C E B O O K

Slide 34

Slide 34 text

F O R C R E AT I N G U S E R I N T E R FA C E S

Slide 35

Slide 35 text

U S I N G C O M P O N E N T S

Slide 36

Slide 36 text

C O M P O N E N T S D O 3 T H I N G S :

Slide 37

Slide 37 text

• R E N D E R • R E C E I V E P R O P S • M A I N TA I N S TAT E C O M P O N E N T S D O 3 T H I N G S :

Slide 38

Slide 38 text

T H I N K PA R T I A L W I T H L O C A L S

Slide 39

Slide 39 text

    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>

Slide 40

Slide 40 text

    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>

Slide 41

Slide 41 text

    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
• Welcome To New York • Blank Space • Style • Out of the Woods • Shake It Off • I Wish You Would • Bad Blood • Wildest Dreams • How You Get the Girl • This Love • I know Places • Clean

Slide 42

Slide 42 text

    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>

Slide 43

Slide 43 text

    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>

Slide 44

Slide 44 text

    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
_songs.html.erb

Slide 45

Slide 45 text

    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
_songs.html.erb

Slide 46

Slide 46 text

<%= render "songs" %>
    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
_songs.html.erb

Slide 47

Slide 47 text

<%= render "songs" %>
    <% @album.songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
_songs.html.erb

Slide 48

Slide 48 text

<%= render "songs" %>
    <% songs .each do |song| %>
  • <%= song.name %>
  • <% end %>
_songs.html.erb

Slide 49

Slide 49 text

_songs.html.erb <%= render "songs" %>
    <% songs.each do |song| %>
  • <%= song.name %>
  • <% end %>

Slide 50

Slide 50 text

<%= render partial: "songs", locals: { songs: @album.songs } %> _songs.html.erb
    <% songs.each do |song| %>
  • <%= song.name %>
  • <% end %>

Slide 51

Slide 51 text

<%= render partial: "songs", locals: { songs: @album.songs } %> _songs.html.erb
    <% songs.each do |song| %>
  • <%= song.name %>
  • <% end %>

Slide 52

Slide 52 text

<%= render partial: "songs", locals: { songs: @album.songs } %> _songs.html.erb
    <% songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
1989 • Welcome To New York • Blank Space • Style • Out of the Woods • Shake It Off • I Wish You Would • Bad Blood • Wildest Dreams • How You Get the Girl • This Love • I know Places • Clean RED • State Of Grace • Red • Treacherous • I Knew You Were Trouble • All Too Well • 22 • I Almost Do • We Are Never Ever Getting Back Together • Stay Stay Stay • The Last Time • … Speak Now • Mine • Sparks Fly • Back To December • Speak Now • Dear John • Mean • The Story Of Us • Never Grow Up • Enchanted • Better Than Revenge • Innocent • Haunted • Last Kiss

Slide 53

Slide 53 text

<% @albums.each do |album| %> <% end %> index.html.erb <%= render partial: "songs", locals: { songs: @album.songs } %>

Slide 54

Slide 54 text

<% @albums.each do |album| %>

<%= album.title %>

<%= render partial: "songs", locals: { songs: album.songs } %> <% end %> index.html.erb <%= render partial: "songs", locals: { songs: @album.songs } %>

Slide 55

Slide 55 text

<% @albums.each do |album| %>

<%= album.title %>

<%= render partial: "songs", locals: { songs: album.songs } %> <% end %> index.html.erb <%= render partial: "songs", locals: { songs: @album.songs } %>

Slide 56

Slide 56 text

Y O U K N O W T H I S

Slide 57

Slide 57 text

L E T ’ S D O I T I N J AVA S C R I P T W I T H R E A C T

Slide 58

Slide 58 text

<%= render partial: "songs", locals: { songs: @album.songs } %> <%= react_component: "Songs", { songs: @album.songs } %>

Slide 59

Slide 59 text

<%= render partial: "songs", locals: { songs: @album.songs } %> <%= react_component: "Songs", { songs: @album.songs } %>

Slide 60

Slide 60 text

<%= render partial: "songs", locals: { songs: @album.songs } %> <%= react_component: "Songs", { songs: @album.songs } %> _songs.html.erb

Slide 61

Slide 61 text

<%= render partial: "songs", locals: { songs: @album.songs } %> <%= react_component: "Songs", { songs: @album.songs } %> _songs.html.erb window.Songs

Slide 62

Slide 62 text

<%= render partial: "songs", locals: { songs: @album.songs } %> <%= react_component: "Songs", { songs: @album.songs } %>

Slide 63

Slide 63 text

<%= render partial: "songs", locals: { songs: @album.songs } %> <%= react_component: "Songs", { songs: @album.songs } %> props

Slide 64

Slide 64 text

P R O P S A R E I M M U TA B L E * kinda

Slide 65

Slide 65 text

L E T ’ S D E F I N E A C O M P O N E N T

Slide 66

Slide 66 text

    <% songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
var Songs

Slide 67

Slide 67 text

    <% songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
var Songs = React.createClass({}); render() {

Slide 68

Slide 68 text

    <% songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
var Songs = React.createClass({ render() { return ; } });

Slide 69

Slide 69 text

    <% songs.each do |song| %>
  • <%= song.name %>
  • <% end %>
var Songs = React.createClass({ render() { return
    ; } });

    Slide 70

    Slide 70 text

      <% songs.each do |song| %>
    • <%= song.name %>
    • <% end %>
    var Songs = React.createClass({ render() { return
      {this.props.songs}
    ; } });

    Slide 71

    Slide 71 text

      <% songs.each do |song| %>
    • <%= song.name %>
    • <% end %>
    var Songs = React.createClass({ render() { return
      {this.props.songs.map()}
    ; } });

    Slide 72

    Slide 72 text

      <% songs.each do |song| %>
    • <%= song.name %>
    • <% end %>
    var Songs = React.createClass({ render() { var createItem = () => return
      {this.props.songs.map(createItem)}
    ; } });

    Slide 73

    Slide 73 text

    var Songs = React.createClass({ render() { var createItem = (song) => ; return
      {this.props.songs.map(createItem)}
    ; } });
      <% songs.each do |song| %>
    • <%= song.name %>
    • <% end %>

    Slide 74

    Slide 74 text

    var Songs = React.createClass({ render() { var createItem = (song) =>
  • {song.name}
  • ; return
      {this.props.songs.map(createItem)}
    ; } });
      <% songs.each do |song| %>
    • <%= song.name %>
    • <% end %>

    Slide 75

    Slide 75 text

    L E T ’ S P R A C T I C E !

    Slide 76

    Slide 76 text

    R E A L - T I M E C O M M E N T S F O R T H E 1 5 - M I N U T E B L O G

    Slide 77

    Slide 77 text

    No content

    Slide 78

    Slide 78 text

    <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 79

    Slide 79 text

    <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 80

    Slide 80 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    {this.props.comment}
    ; } }); <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 81

    Slide 81 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    {this.props.comment}
    ; } }); <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 82

    Slide 82 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    {this.props.comment}
    ; } }); <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 83

    Slide 83 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    ; } }); <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 84

    Slide 84 text

    comment.js.jsx var Comment = React.createClass({ render() { return

    ; } }); <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 85

    Slide 85 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    {this.props.comment}
    ; } }); <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 86

    Slide 86 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    {this.props.comment}
    ; } }); <% @post.comments.each do |comment| %> <%= comment.body %>
    <% end %>

    Slide 87

    Slide 87 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    {this.props.comment}
    ; } }); <% @post.comments.each do |comment| %> <% end %>

    Slide 88

    Slide 88 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    {this.props.comment}
    ; } }); <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %>

    Slide 89

    Slide 89 text

    comment.js.jsx var Comment = React.createClass({ render() { return
    {this.props.comment}
    ; } }); <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %>

    Slide 90

    Slide 90 text

    No content

    Slide 91

    Slide 91 text

    No content

    Slide 92

    Slide 92 text

    No content

    Slide 93

    Slide 93 text

    No content

    Slide 94

    Slide 94 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %>

    Slide 95

    Slide 95 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %>

    Slide 96

    Slide 96 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
      {this.props.comments.map(createItem)}
    ; } });

    Slide 97

    Slide 97 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
      {this.props.comments.map(createItem)}
    ; } });

    Slide 98

    Slide 98 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
      {this.props.comments.map(createItem)}
    ; } });

    Slide 99

    Slide 99 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    ; } });

    Slide 100

    Slide 100 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments}
    ; } });

    Slide 101

    Slide 101 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments.map()}
    ; } });

    Slide 102

    Slide 102 text

    comments.js.jsx var Comments = React.createClass({ render() { var createItem = () => ; return
    {this.props.comments.map(createItem)}
    ; } }); <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %>

    Slide 103

    Slide 103 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments.map(createItem)}
    ; } });

    Slide 104

    Slide 104 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments.map(createItem)}
    ; } });

    Slide 105

    Slide 105 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments.map(createItem)}
    ; } });

    Slide 106

    Slide 106 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments.map(createItem)}
    ; } });

    Slide 107

    Slide 107 text

    <% @post.comments.each do |comment| %> <%= react_component "Comment", { comment: comment.body } %> <% end %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments.map(createItem)}
    ; } });

    Slide 108

    Slide 108 text

    <%= react_component "Comment", { comment: comment.body } %> comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments.map(createItem)}
    ; } });

    Slide 109

    Slide 109 text

    comments.js.jsx var Comments = React.createClass({ render() { var createItem = ({body}) => ; return
    {this.props.comments.map(createItem)}
    ; } }); <%= react_component "Comments", { comments: @post.comments } %>

    Slide 110

    Slide 110 text

    No content

    Slide 111

    Slide 111 text

    No content

    Slide 112

    Slide 112 text

    No content

    Slide 113

    Slide 113 text

    No content

    Slide 114

    Slide 114 text

    G E T T O T H E R E A L - T I M E B I T

    Slide 115

    Slide 115 text

    < C o m m e n t s / > C O M P O N E N T

    Slide 116

    Slide 116 text

    < C o m m e n t / > C O M P O N E N T

    Slide 117

    Slide 117 text

    < C o m m e n t s C o n t a i n e r / > C O M P O N E N T

    Slide 118

    Slide 118 text

    • F E T C H C O M M E N T S • W H I C H C O M P O N E N T R E N D E R S T H E M < C o m m e n t s C o n t a i n e r / > C O M P O N E N T

    Slide 119

    Slide 119 text

    T H I N K O F I T L I K E A R A I L S C O N T R O L L E R

    Slide 120

    Slide 120 text

    <%= react_component "CommentsContainer", commentsPath: comments_post_path(@post) %>

    Slide 121

    Slide 121 text

    <%= react_component "CommentsContainer", commentsPath: comments_post_path(@post) %>

    Slide 122

    Slide 122 text

    <%= react_component "CommentsContainer", commentsPath: comments_post_path(@post) %>

    Slide 123

    Slide 123 text

    var CommentsContainer = React.createClass({ componentWillMount() { this.fetchComments(); setInterval(this.fetchComments, 1000); }, fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ; } });;

    Slide 124

    Slide 124 text

    var CommentsContainer = React.createClass({ componentWillMount() { this.fetchComments(); setInterval(this.fetchComments, 1000); }, fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ; } });

    Slide 125

    Slide 125 text

    var CommentsContainer = React.createClass({ componentWillMount() { this.fetchComments(); setInterval(this.fetchComments, 1000); }, fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ; } });

    Slide 126

    Slide 126 text

    var CommentsContainer = React.createClass({ componentWillMount() { this.fetchComments(); setInterval(this.fetchComments, 1000); }, fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ; } });

    Slide 127

    Slide 127 text

    var CommentsContainer = React.createClass({ componentWillMount() { this.fetchComments(); setInterval(this.fetchComments, 1000); }, fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ; } });

    Slide 128

    Slide 128 text

    var CommentsContainer = React.createClass({ componentWillMount() { this.fetchComments(); setInterval(this.fetchComments, 1000); }, fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ; } });

    Slide 129

    Slide 129 text

    comments_container.js.jsx var CommentsContainer = React.createClass({});

    Slide 130

    Slide 130 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ render() { return ; } });

    Slide 131

    Slide 131 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ render() { return ; } });

    Slide 132

    Slide 132 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ render() { return ; } });

    Slide 133

    Slide 133 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ render() { return ; } }); state

    Slide 134

    Slide 134 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ render() { return ; } });

    Slide 135

    Slide 135 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ getInitialState() { }, render() { return ; } });

    Slide 136

    Slide 136 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ getInitialState() { return { comments: [] }; }, render() { return ; } });

    Slide 137

    Slide 137 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ getInitialState() { return { comments: [] }; }, render() { return ; } });

    Slide 138

    Slide 138 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ;

    Slide 139

    Slide 139 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ;

    Slide 140

    Slide 140 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ;

    Slide 141

    Slide 141 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ; <%= react_component "CommentsContainer", commentsPath: comments_post_path(@post) %>

    Slide 142

    Slide 142 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ;

    Slide 143

    Slide 143 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ;

    Slide 144

    Slide 144 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] }; }, render() { return ;

    Slide 145

    Slide 145 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ componentWillMount() { this.fetchComments(); }, fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() { return { comments: [] };

    Slide 146

    Slide 146 text

    comments_container.js.jsx var CommentsContainer = React.createClass({ componentWillMount() { this.fetchComments(); setInterval(this.fetchComments, 1000); }, fetchComments() { $.getJSON( this.props.commentsPath, (data) => this.setState({comments: data}); ); }, getInitialState() {

    Slide 147

    Slide 147 text

    No content

    Slide 148

    Slide 148 text

    No content

    Slide 149

    Slide 149 text

    No content

    Slide 150

    Slide 150 text

    No content

    Slide 151

    Slide 151 text

    S O H O W M U C H D O Y O U N E E D T O K N O W T O B E E F F E C T I V E ?

    Slide 152

    Slide 152 text

    <%= react_component "Greeting" %> 1

    Slide 153

    Slide 153 text

    <%= react_component "Greeting", name: "Bob" %> 1

    Slide 154

    Slide 154 text

    var Greeting = React.createClass({ render() { return

    Hi {this.props.name}!

    ; } }); 2

    Slide 155

    Slide 155 text

    var Greeting = React.createClass({ render() { return

    Hi {this.props.name}!

    ; } }); 3

    Slide 156

    Slide 156 text

    propTypes 4

    Slide 157

    Slide 157 text

    propTypes: { name: React.PropTypes.string } 4

    Slide 158

    Slide 158 text

    propTypes: { name: React.PropTypes.string } 4

    Slide 159

    Slide 159 text

    propTypes: { name: React.PropTypes.string } 4

    Slide 160

    Slide 160 text

    getDefaultProps() 5

    Slide 161

    Slide 161 text

    getDefaultProps() { return { name: "guest" } } 5

    Slide 162

    Slide 162 text

    getDefaultProps() { return { name: "guest" } } Think of this as ||= in Ruby 5

    Slide 163

    Slide 163 text

    this.setState() 6

    Slide 164

    Slide 164 text

    this.setState() The REFRESH button of React 6

    Slide 165

    Slide 165 text

    getInitialState() { return { comments: [] } } 7

    Slide 166

    Slide 166 text

    componentWillMount() 8

    Slide 167

    Slide 167 text

    componentWillMount() { $.getJSON('/comments.json', handleComments) } 8

    Slide 168

    Slide 168 text

    componentWillMount() componentWillUnmount() 9

    Slide 169

    Slide 169 text

    componentWillMount() { window.addEventListener('scroll', …); }, componentWillUnmount() { window.removeEventListener('scroll', …); } 9

    Slide 170

    Slide 170 text

    componentWillMount() { window.addEventListener('scroll', …); }, componentWillUnmount() { window.removeEventListener('scroll', …); } 9

    Slide 171

    Slide 171 text

    componentWillMount() { source.addEventListener('new-message', …); }, componentWillUnmount() { source.removeEventListener('new-message', …); } 9

    Slide 172

    Slide 172 text

    componentWillMount() { channel.bind('new-message', …); }, componentWillUnmount() { channel.bind('new-message', …); } 9

    Slide 173

    Slide 173 text

    How many APIs 9

    Slide 174

    Slide 174 text

    No content

    Slide 175

    Slide 175 text

    No content

    Slide 176

    Slide 176 text

    No content

    Slide 177

    Slide 177 text

    No content

    Slide 178

    Slide 178 text

    I M P L E M E N TAT I O N

    Slide 179

    Slide 179 text

    R E A C T- R A I L S G E M

    Slide 180

    Slide 180 text

    gem react-rails run rails g react:install R E A C T- R A I L S G E M

    Slide 181

    Slide 181 text

    rails g react:component Greeting R E A C T- R A I L S G E M

    Slide 182

    Slide 182 text

    var Greeting = React.createClass({ render() { return
    ; } }); R E A C T- R A I L S G E M

    Slide 183

    Slide 183 text

    rails g react:component Greeting name:string R E A C T- R A I L S G E M

    Slide 184

    Slide 184 text

    var Greeting = React.createClass({ propTypes: { name: React.PropTypes.string }, render() { return (
    Name: {this.props.name}
    ); } }); R E A C T- R A I L S G E M

    Slide 185

    Slide 185 text

    R A I L S - A S S E T S

    Slide 186

    Slide 186 text

    gem 'sdoc', '~> 0.4.0', group: :doc group :development, :test do gem 'byebug' gem 'web-console', '~> 2.0' gem 'spring' end gem 'react-rails', '~> 1.0' source 'https://rails-assets.org' do gem 'rails-assets-alt' gem 'rails-assets-react-router' gem 'rails-assets-moment' end R A I L S - A S S E T S

    Slide 187

    Slide 187 text

    MISTAKE! F I G H T I N G T H E A S S E T P I P E L I N E

    Slide 188

    Slide 188 text

    TODAY R E A C T- A S S E T S

    Slide 189

    Slide 189 text

    L A N G U A G E

    Slide 190

    Slide 190 text

    var Greeting = React.createClass({ propTypes: { name: React.PropTypes.string }, render() { return (
    Name: {this.props.name}
    ); } }); J S X

    Slide 191

    Slide 191 text

    var Greeting = React.createClass({ propTypes: { name: React.PropTypes.string }, render() { return React.createElement("div", null, React.createElement("div", null, "Name: " + {this.props.name} ); ); } }); J S X

    Slide 192

    Slide 192 text

    var Greeting = React.createClass({ propTypes: { name: React.PropTypes.string }, render() { return (
    Name: {this.props.name}
    ); } }); J S X

    Slide 193

    Slide 193 text

    var Greeting = React.createClass({ propTypes: { name: React.PropTypes.string }, render() { return (
    Name: {this.props.name}
    ); } }); J AVA S C R I P T

    Slide 194

    Slide 194 text

    @Greeting = React.createClass propTypes: name: React.PropTypes.string render: -> `
    Name: {this.props.name}
    ` C O F F E E S C R I P T

    Slide 195

    Slide 195 text

    @Greeting = React.createClass propTypes: name: React.PropTypes.string render: -> `
    Name: {this.props.name}
    ` C O F F E E S C R I P T

    Slide 196

    Slide 196 text

    @Greeting = React.createClass propTypes: name: React.PropTypes.string render: -> `
    Name: {this.props.name}
    ` C O F F E E S C R I P T

    Slide 197

    Slide 197 text

    E S 6 / E S 2 0 1 5 class Greeting extends React.Component { render() { return (
    {this.props.comment}
    ); } } Greeting.propTypes = { comment: React.PropTypes.string };

    Slide 198

    Slide 198 text

    E S 2 0 1 5 class Greeting extends React.Component { render() { return (
    {this.props.comment}
    ); } } Greeting.propTypes = { comment: React.PropTypes.string.isRequired };

    Slide 199

    Slide 199 text

    E S 2 0 1 5 class Greeting extends React.Component { render() { return (
    {this.props.comment}
    ); } } Greeting.propTypes = { comment: React.PropTypes.string.isRequired };

    Slide 200

    Slide 200 text

    E S 6 / E S 2 0 1 5 class Greeting extends React.Component { render() { return (
    {this.props.comment}
    ); } } Greeting.propTypes = { comment: React.PropTypes.string.isRequired };

    Slide 201

    Slide 201 text

    E S 6 / E S 2 0 1 5 class Greeting extends React.Component { getInitialState() { return {foo: "bar"} } render() { return (
    {this.props.comment}
    ); } }

    Slide 202

    Slide 202 text

    E S 6 / E S 2 0 1 5 class Greeting extends React.Component { getInitialState() { return {foo: "bar"} } render() { return (
    {this.props.comment}
    ); } }

    Slide 203

    Slide 203 text

    E S 6 / E S 2 0 1 5 class Greeting extends React.Component { getInitialState() { return {foo: "bar"} } render() { return (
    {this.props.comment}
    ); } }

    Slide 204

    Slide 204 text

    E S 6 / E S 2 0 1 5 class Greeting extends React.Component { constructor() { thas.state = {foo: "bar"} } render() { return (
    {this.props.comment}
    ); } }

    Slide 205

    Slide 205 text

    MISTAKE! E A R LY O N W E B E T A G A I N S T J S X

    Slide 206

    Slide 206 text

    TODAY U S E E S 6 / E S 2 0 1 5 + J S X

    Slide 207

    Slide 207 text

    O N LY A S M U C H J AVA S C R I P T A S Y O U N E E D

    Slide 208

    Slide 208 text

    No content

    Slide 209

    Slide 209 text

    No content

    Slide 210

    Slide 210 text

    No content

    Slide 211

    Slide 211 text

    No content

    Slide 212

    Slide 212 text

    No content

    Slide 213

    Slide 213 text

    No content

    Slide 214

    Slide 214 text

    @ C H A N TA S T I C H I T M E W I T H Q U E S T I O N S

    Slide 215

    Slide 215 text

    Q U E S T I O N S

    Slide 216

    Slide 216 text

    D O Y O U U S E F L U X ? I F S O , W H I C H L I B R A RY ?

    Slide 217

    Slide 217 text

    We do use flux in some of our apps. Those apps use the library Alt. It is incredibly documented, which is great for teams like ours. It’s available an Bower/rails-assets. We try very hard to use the container pattern with for our components. This makes it very easy to use shored components in isolation or inside of a framework like Alt.

    Slide 218

    Slide 218 text

    D O E S R E A C T- R A I L S A L S O A L L O W Y O U T O U S E J S M O D U L E S ?

    Slide 219

    Slide 219 text

    No. To use modules, you’ll need to use an integration like browserify-rails. Practically, browserify-rails dramatically slowed down our apps in development. We weren’t using the interoperability of js modules enough to justify the loss in development speed. We’re basically waitng for something better to come along.

    Slide 220

    Slide 220 text

    D O E S R E A C T H AV E S O M E T Y P E O F C O R R E S P O N D I N G T E S T F R A M E W O R K ?

    Slide 221

    Slide 221 text

    Jest, which is also written by Facebook. Jest is a pretty thin layer around Jasmine, which is great if you know Jasmine. The React library ships with testing utilities, which allows you to work with any testing tool you have comfort with.