├── .gitignore ├── part-1 ├── a.patterns │ ├── build │ │ ├── examples-a.html │ │ ├── examples-b.html │ │ ├── examples-c.html │ │ └── index.html │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── examples-a.js │ │ ├── examples-b.js │ │ └── examples-c.js │ └── webpack.config.js ├── b.first-components │ ├── index.html │ └── readme.md └── readme.md ├── part-2 ├── a.tools │ ├── build │ │ └── index.html │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── Child.js │ │ └── main.js │ └── webpack.config.js ├── b.kata │ ├── react-hn │ │ ├── build │ │ │ ├── NewsHeader.html │ │ │ ├── NewsItem.html │ │ │ ├── NewsList.html │ │ │ ├── css │ │ │ │ ├── NewsHeader.css │ │ │ │ ├── NewsItem.css │ │ │ │ ├── NewsList.css │ │ │ │ └── app.css │ │ │ ├── img │ │ │ │ ├── grayarrow2x.gif │ │ │ │ └── y18.gif │ │ │ └── index.html │ │ ├── package.json │ │ ├── src │ │ │ ├── NewsHeader.js │ │ │ ├── NewsItem.js │ │ │ ├── NewsList.js │ │ │ └── app.js │ │ └── webpack.config.js │ └── readme.md ├── c.communicate │ ├── build │ │ └── index.html │ ├── package.json │ ├── readme.md │ ├── src │ │ ├── Props.js │ │ └── main.js │ └── webpack.config.js └── readme.md ├── part-3 ├── a.upgrade │ └── readme.md ├── b.starter-kits │ └── readme.md └── readme.md └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .draft 3 | 4 | node_modules/ -------------------------------------------------------------------------------- /part-1/a.patterns/build/examples-a.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React Workshop :: React Patterns 5 | 6 | 7 | 8 | 9 |
10 | if you can see this text, React hasn't loaded properly.
11 | check your console 12 |
13 | 14 | -------------------------------------------------------------------------------- /part-1/a.patterns/build/examples-b.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React Workshop :: React Patterns 5 | 6 | 7 | 8 | 9 |
10 | if you can see this text, React hasn't loaded properly.
11 | check your console 12 |
13 | 14 | -------------------------------------------------------------------------------- /part-1/a.patterns/build/examples-c.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React Workshop :: React Patterns 5 | 6 | 7 | 8 | 9 |
10 | if you can see this text, React hasn't loaded properly.
11 | check your console 12 |
13 | 14 | -------------------------------------------------------------------------------- /part-1/a.patterns/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | React Workshop :: React Patterns 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /part-1/a.patterns/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-workshop-starter", 3 | "version": "0.0.1", 4 | "description": "Based on a starter template for webpack and react by Jon Kuperman", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/jkup/webpack-react-starter.git" 8 | }, 9 | "author": "Sherif Abushadi based on work by Jon Kuperman", 10 | "license": "MIT", 11 | "bugs": { 12 | "url": "https://github.com/jkup/webpack-react-starter/issues" 13 | }, 14 | "homepage": "https://github.com/jkup/webpack-react-starter#readme", 15 | "dependencies": { 16 | "react": "^0.14.7", 17 | "react-dom": "^0.14.7", 18 | "webpack-dev-server": "^1.14.0" 19 | }, 20 | "devDependencies": { 21 | "babel-core": "^6.5.2", 22 | "babel-loader": "^6.2.2", 23 | "babel-preset-react":"^6.5.0", 24 | "babel-preset-es2015":"^6.5.0", 25 | "webpack": "^1.12.1" 26 | }, 27 | "scripts": { 28 | "hot": "webpack-dev-server --content-base build/ --inline --hot", 29 | "start": "webpack-dev-server --content-base build/", 30 | "build": "webpack" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /part-1/a.patterns/readme.md: -------------------------------------------------------------------------------- 1 | ### getting started 2 | 3 | ``` 4 | # install the dependencies 5 | npm install 6 | 7 | # start the server 8 | npm run hot 9 | ``` 10 | 11 | ### references / inspiration 12 | 13 | What is React 14 | http://andrewhfarmer.com/what-is-react/ 15 | 16 | Top 5 Tutorials for Getting Started with React 17 | http://andrewhfarmer.com/getting-started-tutorials/ 18 | 19 | 5 Practical Examples For Learning React 20 | http://tutorialzine.com/2014/07/5-practical-examples-for-learning-facebooks-react-framework/ 21 | 22 | React AJAX Best Practices 23 | http://andrewhfarmer.com/react-ajax-best-practices 24 | 25 | AJAX/HTTP Library Comparison 26 | http://andrewhfarmer.com/ajax-libraries 27 | 28 | Making your app fast with high-performance components (React.js Conf 2015) 29 | https://www.youtube.com/watch?v=KYzlpRvWZ6c 30 | 31 | Container Components 32 | https://medium.com/@learnreact/container-components-c0e67432e005#.s5kntzwug 33 | 34 | Presentational and Container Components 35 | https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.gyegbxio9 36 | 37 | React’s JSX: The Other Side of the Coin 38 | https://medium.com/@housecor/react-s-jsx-the-other-side-of-the-coin-2ace7ab62b98#.7e5sfljcn 39 | 40 | webpack-dev-server 41 | http://webpack.github.io/docs/webpack-dev-server.html 42 | - content base 43 | - automatic refresh 44 | - inline mode 45 | - hot module replacement 46 | 47 | ES6 module system (import/export) 48 | http://www.2ality.com/2014/09/es6-modules-final.html 49 | -------------------------------------------------------------------------------- /part-1/a.patterns/src/examples-a.js: -------------------------------------------------------------------------------- 1 | // ES5 with CommonJS style ("current approach") 2 | // var React = require('react') 3 | // var ReactDOM = require('react-dom') 4 | 5 | // ES6 style ("future approach") 6 | import React from 'react' 7 | import ReactDOM from 'react-dom' 8 | 9 | 10 | 11 | /////////////////////////////////////////////////////////////////////////////// 12 | 13 | // All the below are "pure", "stateless" components that take no properties 14 | // and the point of this file is to show you all the varieties of React syntax 15 | // so when you're reading other peoples' code you're not disoriented by it 16 | 17 | /////////////////////////////////////////////////////////////////////////////// 18 | 19 | // this file is structured as follows: 20 | 21 | // ES5 22 | // - React API without JSX 23 | // - JSX feels like HTML 24 | 25 | // - using function declaration 26 | // - using function expression 27 | // - [most common] using React.createClass 28 | // - using Object.create to extend React.Component 29 | 30 | // - using higher order IIFEs (note: anonymous vs. named functions) 31 | 32 | 33 | // ES6 (note: let / const vs var) 34 | // - using arrow functions (note: implicit vs explicit returns) 35 | // - using React.createClass 36 | // - using class syntax to extend React.Component 37 | 38 | 39 | 40 | /////////////////////////////////////////////////////////////////////////////// 41 | // ES5 //////////////////////////////////////////////////////////////////////// 42 | /////////////////////////////////////////////////////////////////////////////// 43 | 44 | // you can write React components using their API without any JSX 45 | function Ex1a(){ 46 | return React.createElement('div', null, 47 | React.createElement('strong', null, 'Ex1a: '), 48 | React.createElement('span', null, 'hello world') 49 | ) 50 | } 51 | 52 | // and you can write the same thing using JSX 53 | function Ex1b(){ 54 | return
Ex1b: hello world
55 | } 56 | 57 | // and if you format it as a hierarchy it feels pretty much like HTML 58 | function Ex1c(){ 59 | return
60 | Ex1c: 61 | hello world 62 |
63 | } 64 | 65 | // as with all 3 examples above, ES5 function declarations work fine 66 | function Ex2(){ 67 | return
this is an ES5 function declaration with JSX in the return statement
68 | } 69 | 70 | // and so do function expressions, both of them properly set "DisplayName" on the component (see React Developer Tools console) 71 | var Ex3 = function(){ 72 | return
this is an ES5 function expression with JSX in the return statement
73 | } 74 | 75 | // but if we use an IIFE to return an anonymous function, our debug output isn't as helpful (see React Developer Tools console) 76 | var Ex4a = (function(){ 77 | return function(){ 78 | return
this is an ES5 IIFE returning an anonymous function with JSX in the return statement
79 | } 80 | }()) 81 | 82 | // unless we name the returned function, in which case we're back to a useful "DisplayName" for the component 83 | var Ex4b = (function(){ 84 | return function Ex4b(){ 85 | return
this is an ES5 IIFE returning a named function with JSX in the return statement
86 | } 87 | }()) 88 | 89 | /////////////////////////////////////////////////////////////////////////////// 90 | // using React.createClass() 91 | /////////////////////////////////////////////////////////////////////////////// 92 | 93 | // by far the most common syntax to create React components is using React.createClass 94 | var Ex5 = React.createClass({ 95 | render: function(){ 96 | return
this example uses React.createClass and implements an explicit render method in ES5
97 | } 98 | }) 99 | 100 | 101 | // - using Object.create to extend React.Component 102 | // found this here: http://www.bennadel.com/blog/3017-extending-react-component-using-es5-with-reactjs-0-14.htm 103 | // but couldn't get it to work. getting complaints about 'prototype' and expect it's a conflict between es6 expecations 104 | // i parsing this file cs es5 syntax. 105 | // var Ex5xxx = {} 106 | 107 | // var Ex5xxx.prototype = Object.create( React.Component.prototype ); 108 | 109 | //// ^ syntax complaints hit here and here ^ 110 | 111 | // function Ex5xxx( initialProps ) { 112 | // React.Component.call( this, initialProps ); 113 | // this.render = render; 114 | // function render() { 115 | // return
this example uses React.createClass and implements an explicit render method in ES5
116 | // } 117 | // } 118 | 119 | 120 | /////////////////////////////////////////////////////////////////////////////// 121 | // using ES6 arrow function expressions to create pure, stateless components 122 | /////////////////////////////////////////////////////////////////////////////// 123 | 124 | // you can also write React components as ES6 functions (assuming you've setup transpiling to ES5) 125 | let Ex6a = () =>
this is an ES6 arrow function with JSX in its implicit return statement
126 | 127 | // notice the difference between 1-liner implicit return above and here, if you use braces you need a return 128 | let Ex6b = () => { 129 | return
this is an ES6 arrow function with JSX in its explicit return statement
130 | } 131 | 132 | // better to use the const keyword since we wouldn't expect these component identifiers to be reassigned 133 | const Ex6c = () =>
just using a const instead of let
134 | 135 | /////////////////////////////////////////////////////////////////////////////// 136 | // using React.createClass() 137 | /////////////////////////////////////////////////////////////////////////////// 138 | 139 | // again, by far the most common syntax if you need anything more than just render() 140 | const Ex7 = React.createClass({ 141 | render(){ 142 | return
using React.createClass from an ES6 method
143 | } 144 | }) 145 | 146 | /////////////////////////////////////////////////////////////////////////////// 147 | // using ES6 classes to extend React.Component 148 | /////////////////////////////////////////////////////////////////////////////// 149 | 150 | class Ex8 extends React.Component { 151 | render(){ 152 | return
and extending React.Component
153 | } 154 | } 155 | 156 | 157 | class Ex9 extends React.Component { 158 | render(){ 159 | return
160 | Ex10: 161 | {' '} 162 | this is an ES6 function using 'div', 'strong' and a spacer 163 |
164 | } 165 | } 166 | 167 | 168 | class Examples extends React.Component { 169 | render(){ 170 | return ( 171 |
172 |

ES5

173 | 174 |
175 | 176 | 177 | 178 | 179 |
180 |

ES6

181 | 182 | 183 | 184 | 185 |
186 | ) 187 | } 188 | } 189 | 190 | 191 | 192 | 193 | ReactDOM.render(, document.querySelector('#container')) 194 | 195 | 196 | // // immediately invoke a function 197 | // (function(){ 198 | // // that creates a listener for window.onload 199 | // window.onload = function(){ 200 | // // and otherwise hides the details of mounting React Components 201 | // var mountPoint = document.querySelector('#container') 202 | 203 | // if (mountPoint) { 204 | // ReactDOM.render(, mountPoint) 205 | // } 206 | // } 207 | // }()) 208 | 209 | -------------------------------------------------------------------------------- /part-1/a.patterns/src/examples-b.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | /////////////////////////////////////////////////////////////////////////////// 5 | 6 | // Now focusing on features of components, let's dig into why / when / how 7 | 8 | /////////////////////////////////////////////////////////////////////////////// 9 | 10 | // - pure/stateless components 11 | // - stateful components 12 | // - container components 13 | // - component lifecycle methods 14 | 15 | 16 | // "pure" (or "stateless") components have no internal state 17 | // but they can receive properties (props) from their owner (wherever they were mounted) 18 | 19 | // as a function, you receive props as an argument 20 | const Ex1a = (props) => { 21 | return
components receive props {props.message}
22 | } 23 | 24 | // when using React.createClass, props are attached to 'this' 25 | const Ex1b = React.createClass({ 26 | render(){ 27 | return
components receive props {this.props.message}
28 | } 29 | }) 30 | 31 | // when extending React.Component you have to call super() and pass props 32 | class Ex1c extends React.Component { 33 | constructor(props){ 34 | super(props) 35 | } 36 | 37 | render(){ 38 | return
components receive props {this.props.message}
39 | } 40 | } 41 | 42 | // "stateful" components have some internal state that they manage 43 | 44 | // when defining components as a function, you *can't* manage state (as of React 0.14) 45 | const Ex2zzz = () => { 46 | // functions can't manage state, they're only good for pure components 47 | } 48 | 49 | // state requires an additional method: getInitialState() 50 | // ... it's like your default settings for the component 51 | const Ex2a = React.createClass({ 52 | getInitialState(){ 53 | return {data: 'their own internal state'} 54 | }, // notice the comma here since we're inside an object literal 55 | 56 | render(){ 57 | return
components can manage {this.state.data}
58 | } 59 | }) 60 | 61 | // when extending React.Component you have to call super() and pass props 62 | class Ex2b extends React.Component { 63 | constructor(){ 64 | super() 65 | this.state = {data: 'their own state'} 66 | } // notice, no comma since we're inside a class definition 67 | 68 | render(){ 69 | return
component can manage {this.state.data}
70 | } 71 | } 72 | 73 | 74 | // but what makes state interesting is that it can change over time 75 | const Ex3 = React.createClass({ 76 | getInitialState(){ 77 | return {clickCount: 0} 78 | }, 79 | 80 | render(){ 81 | let inc = () => this.setState({clickCount: this.state.clickCount + 1}) 82 | 83 | return
84 | components can track data like this: [{this.state.clickCount}] click anywhere in this blue box and watch the number grow 85 |
86 | } 87 | }) 88 | 89 | 90 | // the same thing can be automated using setInterval 91 | const Ex4a = React.createClass({ 92 | getInitialState(){ 93 | return { count: 0 } 94 | }, 95 | 96 | // we need other lifecycle methods now to place our timer code 97 | componentDidMount(){ 98 | let inc = () => this.setState({count: this.state.count + 1}) 99 | this.timerId = setInterval(inc, 1000) 100 | 101 | setTimeout(() => clearInterval(this.timerId), 5000) 102 | }, 103 | 104 | // and to clear our timer code if the component ever leaves the page 105 | componentWillUnmount(){ 106 | clearInterval(this.timerId) 107 | }, 108 | 109 | render(){ 110 | return
111 | components can track data like this: [{this.state.count}] <-- counts up to 5 (refresh the page if you missed it) 112 |
113 | } 114 | }) 115 | 116 | 117 | // shouldComponentUpdate() is a kind of "guard" method that can stop the component 118 | // from refreshing depending on what it returns. false: don't refresh. default is true 119 | // and you would use this to optimize the rendering of your component. 120 | // look at the logs to see the arguments passed to this method 121 | const Ex4b = React.createClass({ 122 | getInitialState(){ 123 | return {count: 0} 124 | }, 125 | 126 | componentDidMount(){ 127 | // increment the count every second 128 | this.timerId = setInterval(this.inc, 1000) 129 | // stop incrementing after 5 seconds 130 | setTimeout(() => clearInterval(this.timerId), 5000) 131 | }, 132 | 133 | inc(){ 134 | this.setState({count: this.state.count + 1}) 135 | }, 136 | 137 | componentWillUnmount(){ 138 | clearInterval(this.timerId) 139 | }, 140 | 141 | shouldComponentUpdate(){ 142 | return false // this component never updates because this method returns false every time 143 | }, 144 | 145 | render(){ 146 | return
147 | components can track data like this: [{this.state.count}] <-- but this wont update 148 |
149 | } 150 | }) 151 | 152 | 153 | 154 | const Ex4c = React.createClass({ 155 | getInitialState(){ 156 | return { elapsedTime: 0 } 157 | }, 158 | 159 | componentDidMount(){ 160 | this.timerId = setInterval(this.updateTime, 100) 161 | }, 162 | 163 | componentWillUnmount(){ 164 | clearInterval(this.timerId) 165 | }, 166 | 167 | updateTime(){ 168 | // calculate time passed since 'start' in seconds 169 | let elapsedTime = (((new Date() - this.props.start)/1000) % 60).toFixed(1) 170 | 171 | this.setState({ elapsedTime }) 172 | }, 173 | 174 | shouldComponentUpdate(){ 175 | let et = this.state.elapsedTime 176 | if(et >= 2 && et <= 4) return false // stop updating between 2 and 4 seconds 177 | 178 | return true 179 | }, 180 | 181 | render(){ 182 | return
183 | components can track data like this: [{this.state.elapsedTime}]{' '} 184 | 185 |
186 | } 187 | }); 188 | 189 | 190 | const Ex5 = React.createClass({ 191 | 192 | style: { 193 | display: 'flex', 194 | flexDirection: 'column', 195 | // justifyContent: 'space-around', 196 | backgroundColor: 'lightgrey', 197 | border: '1px solid blue', 198 | padding: '10px', 199 | margin: '10px' 200 | }, 201 | 202 | getInitialState(){ 203 | return { focused: 0 } 204 | }, 205 | 206 | clicked(index){ 207 | this.setState({focused: index}) 208 | }, 209 | 210 | render() { 211 | // The map method will loop over the array of menu entries, 212 | // and will return a new array with
  • elements. 213 | let listItems = this.props.items.map((m, index) => { 214 | 215 | return
  • {m}
  • ; 216 | }) 217 | 218 | return ( 219 |
    220 | click a list item and see its name appear below 221 |
      { listItems }
    222 |

    {this.props.items[this.state.focused]}

    223 |
    224 | ); 225 | } 226 | }); 227 | 228 | const Ex6 = () => 229 | 230 | const CommentPanel = React.createClass({ 231 | getInitialState(){ 232 | return { 233 | comments: ['hi', 'hey', 'ho'] 234 | } 235 | }, 236 | 237 | addComment(c){ 238 | let comments = this.state.comments 239 | comments.push(c) 240 | 241 | this.setState({ comments }) // ES6 simplified object notation 242 | }, 243 | 244 | render(){ 245 | let comments = this.state.comments.map((c,idx) => { 246 | return 247 | }) 248 | 249 | return
    250 |

    Comments

    251 |
      { comments }
    252 | 253 |
    254 | } 255 | }) 256 | 257 | const Comment = (props) =>
  • {props.text}
  • 258 | 259 | const CommentForm = React.createClass({ 260 | submit(e){ 261 | e.preventDefault() 262 | 263 | let comment = this.refs.new_comment.value 264 | this.props.add(comment) 265 | }, 266 | 267 | render(){ 268 | return
    269 | 270 | 271 |
    272 | } 273 | }) 274 | 275 | 276 | // ... more on lifecycle methods 277 | // ... fetching data from outside 278 | // ... add 8 ways to communicate stuff here too 279 | // "container" components wrap "pure" components and provide access to the external world 280 | 281 | class Examples extends React.Component { 282 | render(){ 283 | return
    284 | 285 | 286 | 287 |
    288 | 289 | 290 |
    291 | 292 | 293 |
    294 | 295 | 296 |
    297 | } 298 | } 299 | 300 | 301 | // immediately invoke a function 302 | (function(){ 303 | // that creates a listener for window.onload 304 | window.onload = function(){ 305 | // and otherwise hides the details of mounting React Components 306 | var mountPoint = document.querySelector('#container') 307 | 308 | if (mountPoint) { 309 | ReactDOM.render(, mountPoint) 310 | } 311 | } 312 | }()) 313 | -------------------------------------------------------------------------------- /part-1/a.patterns/src/examples-c.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | /////////////////////////////////////////////////////////////////////////////// 5 | 6 | // Now focusing on moving data around 7 | 8 | /////////////////////////////////////////////////////////////////////////////// 9 | 10 | 11 | // 8 no-Flux strategies for React component communication 12 | // http://andrewhfarmer.com/component-communication 13 | 14 | // React AJAX Best Practices 15 | // http://andrewhfarmer.com/react-ajax-best-practices 16 | 17 | // AJAX/HTTP Library Comparison 18 | // http://andrewhfarmer.com/ajax-libraries 19 | 20 | class Examples extends React.Component { 21 | render(){ 22 | return
    no react components here yet ...
    23 | } 24 | } 25 | 26 | // immediately invoke a function 27 | (function(){ 28 | // that creates a listener for window.onload 29 | window.onload = function(){ 30 | // and otherwise hides the details of mounting React Components 31 | var mountPoint = document.querySelector('#container') 32 | 33 | if (mountPoint) { 34 | ReactDOM.render(, mountPoint) 35 | } 36 | } 37 | }()) -------------------------------------------------------------------------------- /part-1/a.patterns/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var config = { 3 | entry: { 4 | 'examples-a': path.resolve(__dirname, 'src/examples-a.js'), 5 | 'examples-b': path.resolve(__dirname, 'src/examples-b.js'), 6 | 'examples-c': path.resolve(__dirname, 'src/examples-c.js') 7 | 8 | }, 9 | output: { 10 | path: path.resolve(__dirname, 'build'), 11 | filename: "[name].js", 12 | publicPath: "/" 13 | }, 14 | module: { 15 | loaders: [{ 16 | test: /\.jsx?$/, 17 | loader: 'babel', 18 | query: { 19 | presets: ['es2015', 'react'] 20 | } 21 | }] 22 | } 23 | }; 24 | 25 | 26 | module.exports = config; -------------------------------------------------------------------------------- /part-1/b.first-components/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Your First Component 5 | 6 | 7 | 8 | 9 | 10 | 11 |
    12 | 13 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /part-1/b.first-components/readme.md: -------------------------------------------------------------------------------- 1 | ### getting started 2 | 3 | **installation** 4 | 5 | There is no installation! 6 | 7 | Just open the `index.html` file and do your work there to keep things simple 8 | 9 | 10 | ### references / inspiration 11 | 12 | Thinking in React (official Facebook tutorial, it's excellent) 13 | https://facebook.github.io/react/docs/thinking-in-react.html 14 | 15 | React examples 16 | http://www.reactexamples.com/tag/react 17 | 18 | Component Playground (embed your own components & their source code on a page) 19 | http://stack.formidable.com/component-playground/ 20 | 21 | Awesome React (the list of lists) 22 | https://github.com/enaqx/awesome-react 23 | 24 | Thoughts on what to watch out for (best practices) 25 | https://blog.risingstack.com/react-js-best-practices-for-2016/ -------------------------------------------------------------------------------- /part-1/readme.md: -------------------------------------------------------------------------------- 1 | ## Developer Week :: React Workshop 2 | 3 | > delivered Wednesday, Feb 17, 2016 4 | > based on React 0.14 5 | > created by Sherif Abushadi (sherif@devbootcamp.com) 6 | 7 | --- 8 | 9 | ### timing 10 | - 9 am - 9:50 am 11 | 12 | 13 | ### slides 14 | 15 | [slides are here](https://docs.google.com/presentation/d/1ttAyxWIooMqY4tTHqlqTMk9dnhP4fWD-j7dmJwVQDvI/edit?usp=sharing) 16 | 17 | 18 | ### outcomes 19 | - **you will be able to explain what React is and how it might have a place in your web application development story** 20 | - **you will be able to read and understand the majority of React-specific source code of any web application that uses React** 21 | - **you will be able to create your own custom components using several syntactic variants with ES5 and ES6** 22 | 23 | 24 | ### part 1: orientation 25 | 26 | - [10 mins] we begin with a brief overview of what React is exactly, the kinds of problems it was intended to solve and why so many experienced developers like it 27 | - [20 mins] next we take a look at the common patterns of creating, connecting and organizing React components including `React.createClass()`, extending `React.Component` and creating pure components using JavaScript functions 28 | - [20 mins] finally, you get to build your first React components using one of our ideas or your own as a target for development 29 | 30 | 31 | ### getting started 32 | 33 | **online** 34 | 35 | > you can use the online version here: http://jsfiddle.net/user/amgando/ 36 | 37 | **installation** 38 | 39 | ``` 40 | # install the dependencies 41 | npm install 42 | 43 | # start the server 44 | npm run hot 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /part-2/a.tools/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Getting to Know npm and Webpack 5 | 6 | 7 | 8 |
    9 | if you can read this then React isn't working yet 10 |
    11 | 12 | -------------------------------------------------------------------------------- /part-2/a.tools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "build-tools", 3 | "version": "0.0.1", 4 | "description": "getting started with npm and webpack", 5 | "author": "Sherif Abushadi", 6 | "homepage": "https://github.com/amgando/react-workshop", 7 | "dependencies": { 8 | "react": "^0.14.7", 9 | "react-dom": "^0.14.7", 10 | "webpack-dev-server": "^1.14.0" 11 | }, 12 | "devDependencies": { 13 | "babel-core": "^6.5.2", 14 | "babel-loader": "^6.2.2", 15 | "babel-preset-es2015": "^6.5.0", 16 | "babel-preset-react": "^6.5.0", 17 | "webpack": "^1.12.1" 18 | }, 19 | "scripts": { 20 | "hot": "webpack-dev-server --content-base build/ --inline --hot", 21 | "start": "webpack-dev-server --content-base build/", 22 | "build": "webpack" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /part-2/a.tools/readme.md: -------------------------------------------------------------------------------- 1 | your goal is to get to know npm and Webpack 2 | 3 | 4 | ### getting started 5 | 6 | ``` 7 | # install the dependencies 8 | npm install 9 | 10 | # start the server 11 | npm start 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /part-2/a.tools/src/Child.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | export default class Child extends React.Component { 5 | constructor(props){ 6 | super(props) 7 | } 8 | 9 | render() { 10 | return
    hello from *{this.props.name}* child component
    11 | } 12 | } 13 | -------------------------------------------------------------------------------- /part-2/a.tools/src/main.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | import Child from './Child' 5 | 6 | const MyComponent = () => { 7 | return
    8 |

    Hello World

    9 | 10 | 11 | 12 |
    13 | } 14 | 15 | ReactDOM.render(, document.querySelector('#container')) 16 | -------------------------------------------------------------------------------- /part-2/a.tools/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var config = { 4 | entry: path.resolve(__dirname, 'src/main.js'), 5 | output: { 6 | path: path.resolve(__dirname, 'build'), 7 | filename: "main.js", 8 | publicPath: "/" 9 | }, 10 | module: { 11 | loaders: [{ 12 | test: /\.jsx?$/, 13 | loader: 'babel', 14 | query: { 15 | presets: ['es2015', 'react'] 16 | } 17 | }] 18 | } 19 | }; 20 | 21 | module.exports = config; -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/NewsHeader.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NewsHeader 6 | 7 | 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/NewsItem.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NewsItem 6 | 7 | 8 | 9 | 10 |
    11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/NewsList.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NewsList 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/css/NewsHeader.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Verdana, sans-serif; 3 | } 4 | 5 | .newsHeader { 6 | align-items: center; 7 | background: #ff6600; 8 | color: black; 9 | display: flex; 10 | font-size: 10pt; 11 | padding: 2px; 12 | } 13 | 14 | .newsHeader-login { 15 | margin-right: 5px; 16 | } 17 | 18 | .newsHeader-logo { 19 | border: 1px solid white; 20 | flex-basis: 18px; 21 | height: 18px; 22 | } 23 | 24 | .newsHeader-nav { 25 | flex-grow: 1; 26 | margin-left: 10px; 27 | } 28 | 29 | .newsHeader-navLink:not(:first-child)::before { 30 | content: ' | '; 31 | } 32 | 33 | .newsHeader-textLink { 34 | color: black; 35 | text-decoration: none; 36 | } 37 | 38 | .newsHeader-title > a { 39 | font-weight: bold; 40 | margin-left: 4px; 41 | } 42 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/css/NewsItem.css: -------------------------------------------------------------------------------- 1 | .newsItem { 2 | align-items: baseline; 3 | color: #828282; 4 | display: flex; 5 | margin-top: 5px; 6 | } 7 | 8 | .newsItem-domain { 9 | font-size: 8pt; 10 | margin-left: 5px; 11 | } 12 | 13 | .newsItem-itemText { 14 | flex-grow: 1; 15 | } 16 | 17 | .newsItem-rank { 18 | flex-basis: 25px; 19 | font-size: 10pt; 20 | text-align: right; 21 | } 22 | 23 | .newsItem-subtext { 24 | font-size: 7pt; 25 | } 26 | 27 | .newsItem-subtext > a { 28 | color: #828282; 29 | text-decoration: none; 30 | } 31 | 32 | .newsItem-subtext > a:hover { 33 | text-decoration: underline; 34 | } 35 | 36 | .newsItem-titleLink { 37 | color: black; 38 | font-size: 10pt; 39 | text-decoration: none; 40 | } 41 | 42 | .newsItem-vote { 43 | flex-basis: 15px; 44 | text-align: center; 45 | } 46 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/css/NewsList.css: -------------------------------------------------------------------------------- 1 | .newsList { 2 | background: #f6f6ef; 3 | margin-left: auto; 4 | margin-right: auto; 5 | width: 85%; 6 | } 7 | 8 | .newsList-more { 9 | margin-left: 40px; /* matches NewsItem rank and vote */ 10 | margin-top: 10px; 11 | padding-bottom: 10px; 12 | } 13 | 14 | .newsList-moreLink { 15 | color: black; 16 | font-size: 10pt; 17 | text-decoration: none; 18 | } 19 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/css/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Verdana, sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/img/grayarrow2x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amgando/react-workshop/321965b2b6dd5e3dbf67ef1ea197fae0c77f6e92/part-2/b.kata/react-hn/build/img/grayarrow2x.gif -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/img/y18.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amgando/react-workshop/321965b2b6dd5e3dbf67ef1ea197fae0c77f6e92/part-2/b.kata/react-hn/build/img/y18.gif -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hacker News 6 | 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-hn", 3 | "version": "0.1.0", 4 | "description": "Based on a react-hn tutorial by Matthew King", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/mking/react-hn.git" 8 | }, 9 | "author": "Sherif Abushadi based on work by Matthew King", 10 | "homepage": "https://github.com/mking/react-hn", 11 | "dependencies": { 12 | "react": "^0.14.7", 13 | "react-dom": "^0.14.7", 14 | "webpack-dev-server": "^1.14.0", 15 | "moment": "^2.11.2", 16 | "url": "^0.11.0" 17 | }, 18 | "devDependencies": { 19 | "babel-core": "^6.5.2", 20 | "babel-loader": "^6.2.2", 21 | "babel-preset-es2015": "^6.5.0", 22 | "babel-preset-react": "^6.5.0", 23 | "webpack": "^1.12.1" 24 | }, 25 | "scripts": { 26 | "hot": "webpack-dev-server --content-base build/ --inline --hot", 27 | "start": "webpack-dev-server --content-base build/", 28 | "build": "webpack" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/src/NewsHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | export default class NewsHeader extends React.Component { 5 | render() { 6 | return ( 7 |
    8 | 9 | 10 | <Navigation /> 11 | <Login /> 12 | </div> 13 | ); 14 | } 15 | }; 16 | 17 | 18 | /* 19 | #componentkata 20 | 21 | take a look at the next 5 components, they're all the same. 22 | 23 | each one is written in a different style. 24 | 25 | if you want to get better at recognizing these variations, 26 | just repeat the same exercise for as many of these components as you like 27 | 28 | */ 29 | 30 | // name: Logo 31 | // type: pure [ pure | stateful | container ] 32 | 33 | 34 | 35 | // ES5 function declaration 36 | function Logo(){ 37 | return <div className="newsHeader-logo"> 38 | <a href="https://www.ycombinator.com"><img src="/img/y18.gif"/></a> 39 | </div> 40 | } 41 | 42 | // ES5 function expression 43 | // var Logo = function(){ 44 | // return <div className="newsHeader-logo"> 45 | // <a href="https://www.ycombinator.com"><img src="/img/y18.gif"/></a> 46 | // </div> 47 | // } 48 | 49 | // ES5 using React.createClass 50 | // var Logo = React.createClass({ 51 | // render: function(){ 52 | // return <div className="newsHeader-logo"> 53 | // <a href="https://www.ycombinator.com"><img src="/img/y18.gif"/></a> 54 | // </div> 55 | // } 56 | // }) 57 | 58 | 59 | 60 | // ES6 using arrow functions 61 | // const Logo = () => { 62 | // return <div className="newsHeader-logo"> 63 | // <a href="https://www.ycombinator.com"><img src="/img/y18.gif"/></a> 64 | // </div> 65 | // } 66 | 67 | // ES6 using React.createClass 68 | // const Logo = React.createClass({ 69 | // render(){ 70 | // return <div className="newsHeader-logo"> 71 | // <a href="https://www.ycombinator.com"><img src="/img/y18.gif"/></a> 72 | // </div> 73 | // } 74 | // }) 75 | 76 | // ES6 using class syntax to extend React.Component 77 | // class Logo extends React.Component { 78 | // render(){ 79 | // return <div className="newsHeader-logo"> 80 | // <a href="https://www.ycombinator.com"><img src="/img/y18.gif"/></a> 81 | // </div> 82 | // } 83 | // } 84 | 85 | 86 | const Title = () => { 87 | return <div className="newsHeader-title"> 88 | <a className="newsHeader-textLink" href="https://news.ycombinator.com">Hacker News</a> 89 | </div> 90 | } 91 | 92 | const Navigation = () => { 93 | var navLinks = [ 94 | {id: 1, name: 'new', url: 'newest' }, 95 | {id: 2, name: 'comments', url: 'newcomments' }, 96 | {id: 3, name: 'show', url: 'show' }, 97 | {id: 4, name: 'ask', url: 'ask' }, 98 | {id: 5, name: 'jobs', url: 'jobs' }, 99 | {id: 6, name: 'submit', url: 'submit' }, 100 | ]; 101 | 102 | return ( 103 | <div className="newsHeader-nav"> 104 | {navLinks.map(function ({id, name, url}) { 105 | 106 | let linkUrl = 'https://news.ycombinator.com/' + url 107 | 108 | return ( 109 | <a key={id} className="newsHeader-navLink newsHeader-textLink" href={linkUrl}> 110 | {name} 111 | </a> 112 | ); 113 | })} 114 | </div> 115 | ); 116 | } 117 | 118 | const Login = () => { 119 | return <div className="newsHeader-login"> 120 | <a className="newsHeader-textLink" href="https://news.ycombinator.com/login?whence=news">login</a> 121 | </div> 122 | } 123 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/src/NewsItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | import moment from 'moment' 5 | import { default as url_helper } from 'url' 6 | 7 | export default class NewsItem extends React.Component { 8 | constructor(props){ 9 | super(props) 10 | } 11 | 12 | render() { 13 | return ( 14 | <div className="newsItem"> 15 | <Rank rank={this.props.rank} /> 16 | <Vote item={this.props.item} /> 17 | <div className="newsItem-itemText"> 18 | <Title item={this.props.item} /> 19 | <Subtext item={this.props.item} /> 20 | </div> 21 | </div> 22 | ) 23 | } 24 | } 25 | 26 | const Rank = (props) => <div className="newsItem-rank">{props.rank}</div> 27 | 28 | const Vote = (props) => { 29 | let link = 'https://news.ycombinator.com/vote?for=' + props.item.id + '&dir=up&whence=news' 30 | 31 | return ( 32 | <div className="newsItem-vote"> 33 | <a href={link}><img src="/img/grayarrow2x.gif" width="10"/></a> 34 | </div> 35 | ) 36 | } 37 | 38 | 39 | const Title = (props) => { 40 | let domain = url_helper.parse(props.item.url).hostname 41 | let { url, title } = props.item 42 | 43 | return ( 44 | <div className="newsItem-title"> 45 | <a className="newsItem-titleLink" href={url}>{title}</a> 46 | <span className="newsItem-domain">({domain})</span> 47 | </div> 48 | ) 49 | } 50 | 51 | const Subtext = (props) => { 52 | let by = 'https://news.ycombinator.com/user?id=' + props.item.by 53 | let posted = moment(props.item.time * 1000).fromNow() 54 | 55 | return <div className="newsItem-subtext"> 56 | {props.item.score} points by <a href={by}>{props.item.by}</a> {posted} | {<CommentLink item={props.item} />} 57 | </div> 58 | } 59 | 60 | 61 | const CommentLink = (props) => { 62 | let commentText = 'discuss' 63 | 64 | if (props.item.kids && props.item.kids.length) { 65 | commentText = props.item.kids.length + ' comments' 66 | } 67 | 68 | return ( 69 | <a href={'https://news.ycombinator.com/item?id=' + props.item.id}>{commentText}</a> 70 | ) 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/src/NewsList.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import NewsItem from './NewsItem' 4 | import NewsHeader from './NewsHeader' 5 | 6 | export default class NewsList extends React.Component { 7 | constructor(props){ 8 | super(props) 9 | } 10 | 11 | render() { 12 | let items = this.props.items.map((item, index) => { 13 | return <NewsItem key={item.id} item={item} rank={index + 1} /> 14 | }); 15 | return ( 16 | <div className="newsList"> 17 | <NewsHeader/> 18 | <div className="newsList-items">{items}</div> 19 | <More /> 20 | </div> 21 | ); 22 | } 23 | } 24 | 25 | 26 | const More = () => { 27 | return ( 28 | <div className="newsList-more"> 29 | <a className="newsList-moreLink" href="https://news.ycombinator.com/news?p=2">More</a> 30 | </div> 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/src/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | import NewsList from './NewsList' 5 | 6 | // fake data here instead of fetching it from remote source 7 | let items = [{"by":"jamesisaac","id":8805053,"kids":[8805325,8805679,8805195,8805408,8805681,8805650,8805643,8805577,8805469,8805204,8805222,8805498,8805190,8805304,8805569,8805328,8805478,8805350,8805186,8805432,8805318,8805480,8805320,8805601,8805106],"score":167,"text":"","time":1419737448,"title":"Look, no hands","type":"story","url":"http://looknohands.me/"},{"by":"jcr","id":8805606,"score":10,"text":"","time":1419750879,"title":"Psychologists Strike a Blow for Reproducibility","type":"story","url":"http://www.nature.com/news/psychologists-strike-a-blow-for-reproducibility-1.14232/"},{"by":"lelf","id":8802424,"kids":[8802475,8804091,8802511,8802500,8805677,8802481,8804771,8802746,8804040,8803150,8805382,8802739,8802597,8802644,8802987,8802722,8805123,8805545,8802484,8802716,8802505,8802687,8805135,8803538,8804569,8804707,8802504,8802499,8803836,8803653,8802781,8802613,8803595,8803216,8804402,8802626,8803875,8804191,8802491,8804898,8804004,8803701,8804551,8802522,8802570,8802877,8802657,8802533,8802636,8802659,8802537,8802827,8802774,8803511,8802905,8802550,8802601,8803205,8804487,8802554,8803290,8803152,8804425,8802686,8802557,8802478,8803004,8802480,8804231,8802494,8803114,8802488,8803737,8802553,8804442,8802816,8804240,8803715,8803112,8802831,8803018,8802498,8803555,8803592,8803231],"score":608,"text":"","time":1419685280,"title":"Adblock Plus is probably the reason Firefox and Chrome are such memory hogs","type":"story","url":"http://www.extremetech.com/computing/182428-ironic-iframes-adblock-plus-is-probably-the-reason-firefox-and-chrome-are-such-memory-hogs"},{"by":"gscott","id":8804127,"kids":[8805695,8804783,8804448,8804580,8805479,8805141,8804363,8804561,8805227,8804582,8804937,8804696],"score":120,"text":"","time":1419717862,"title":"How Colonel Sanders Became Father Christmas in Japan","type":"story","url":"http://talkingpointsmemo.com/ts/kfc-christmas-in-japan-colonel-sanders-history-12-23-2014"},{"by":"getdavidhiggins","id":8805039,"kids":[8805113,8805501,8805231],"score":34,"text":"","time":1419736952,"title":"Redesiging a Broken Internet: Cory Doctorow [video]","type":"story","url":"https://www.youtube.com/watch?v=_J_9EFGFR-Y"},{"by":"davidbarker","id":8804691,"kids":[8805070,8805429,8805035,8804964],"score":54,"text":"","time":1419729238,"title":"A Primer on Bézier Curves (2013)","type":"story","url":"http://pomax.github.io/bezierinfo/"},{"by":"nkurz","id":8804961,"kids":[8805214,8805634,8805248,8805541],"score":27,"text":"","time":1419734983,"title":"How Google Cracked House Number Identification in Street View","type":"story","url":"http://www.technologyreview.com/view/523326/how-google-cracked-house-number-identification-in-street-view/"},{"by":"superfx","id":8804824,"score":10,"text":"","time":1419731802,"title":"Jeff Hawkins: Brains, Data, and Machine Intelligence [video]","type":"story","url":"https://www.youtube.com/watch?v=cz-3WDdqbj0"},{"by":"danso","id":8802676,"kids":[8803169,8803141,8804121,8803753,8803115,8803523,8804504,8804102,8803157,8803733],"score":240,"text":"","time":1419691704,"title":"The Wire in HD","type":"story","url":"http://davidsimon.com/the-wire-hd-with-videos/"},{"by":"theoutlander","id":8804909,"kids":[8805693,8805550],"score":23,"text":"","time":1419733513,"title":"Chicago gave hundreds of high-risk kids a job; violent crime arrests plummeted","type":"story","url":"http://www.washingtonpost.com/blogs/wonkblog/wp/2014/12/26/chicago-gave-hun…t-crime-arrests-plummeted/?Post+generic=%3Ftid%3Dsm_twitter_washingtonpost"},{"by":"moe","id":8803998,"kids":[8804028,8804859,8804528,8804521,8804591],"score":63,"text":"Tobias Engel demonstrates (amongst other things):<p>* How to find out the phone numbers of nearby cellphones<p>* How to track the location of a cellphone that you only know the phone number of<p>* How intercept outgoing calls of nearby cellphones","time":1419715606,"title":"SS7: Locate. Track. Manipulate [video]","type":"story","url":"http://streaming.media.ccc.de/relive/6249/"},{"by":"jwatte","id":8803235,"kids":[8803652,8804123,8804262,8804421,8804287,8804144,8803910],"score":114,"text":"","time":1419702205,"title":"The Real-time Web: How to Get Millisecond Updates with REST","type":"story","url":"http://engineering.imvu.com/2014/12/27/the-real-time-web-in-rest-services-at-imvu/"},{"by":"pmoriarty","id":8803498,"kids":[8804214,8805055,8804229,8804041,8804008,8804753,8804990,8804173,8804042,8804997,8803959,8804450],"score":91,"text":"","time":1419706531,"title":"Masscan: Scan the entire Internet in under 5 minutes","type":"story","url":"https://github.com/robertdavidgraham/masscan"},{"by":"Thevet","id":8804296,"kids":[8804610,8805631,8804717,8804483,8804874,8804748,8804475,8804914,8804447,8804790,8805257,8804623,8805051],"score":41,"text":"","time":1419721241,"title":"Home for the holidays, and for a 20-year-old issue of PC Magazine","type":"story","url":"http://www.theverge.com/tldr/2014/12/26/7451295/home-for-the-holidays-and-for-a-20-year-old-issue-of-pc-magazine"},{"by":"lkrubner","id":8803101,"kids":[8805105,8805658,8804495,8803794,8804347,8805289,8805524,8804793,8804247,8804968,8804106,8805271,8804665,8805031,8804642,8805434,8804814,8803946,8804259,8804826,8804875,8804013,8803833],"score":89,"text":"","time":1419699685,"title":"When rational thinking is correlated with intelligence the correlation is modest","type":"story","url":"http://www.scientificamerican.com/article/rational-and-irrational-thought-the-thinking-that-iq-tests-miss/"},{"by":"ColinWright","id":8803138,"kids":[8805684,8803829,8805200,8803761,8804051,8804965,8804311],"score":96,"time":1419700378,"title":"Apollo 11 Flight Plan – Final [pdf]","type":"story","url":"https://www.hq.nasa.gov/alsj/a11/a11fltpln_final_reformat.pdf"},{"by":"r0h1n","id":8805394,"score":7,"text":"","time":1419744647,"title":"The Slow Death of ‘Do Not Track’","type":"story","url":"http://nytimes.com/2014/12/27/opinion/the-slow-death-of-do-not-track.html"},{"by":"waffle_ss","id":8804624,"kids":[8804895,8804788,8804923,8804784,8805077,8805691,8804729,8804989,8804931,8804763,8804940,8804780,8804764,8804868,8804956,8804982,8804935],"score":150,"text":"","time":1419727453,"title":"James Golick has died","type":"story","url":"https://twitter.com/jill380/status/548978785404874753"},{"by":"lelf","id":8802290,"kids":[8805536,8803376,8803757,8803307,8803438,8804667,8803619,8803647,8804264,8804609,8804218,8804222,8803633],"score":91,"time":1419678666,"title":"Patients do better when cardiologists are away at academic meetings","type":"story","url":"http://theincidentaleconomist.com/wordpress/patients-do-better-when-cardiologists-are-away-at-academic-meetings/"},{"by":"MichaelAO","id":8801616,"kids":[8801839,8803710,8802569,8801827,8802483,8804177,8801852,8801823,8802186,8802059,8802072,8803818,8802058,8801819,8802178,8801828,8801973],"score":240,"text":"","time":1419652028,"title":"Slow, flexible and cheap: Six years of development to create a rubber hexagon","type":"story","url":"https://medium.com/dome-kit/slow-flexible-cheap-5598ca91fb38"},{"by":"frostmatthew","id":8804934,"kids":[8805042,8805075,8805120,8805591,8805509,8805056,8805084,8805556,8805224,8805089,8805187,8805061,8805274,8805101,8805193,8805463,8805064,8805338,8805109,8805063,8805071,8805067],"score":165,"text":"","time":1419734117,"title":"On Immigration, Engineers Simply Don’t Trust VCs","type":"story","url":"http://techcrunch.com/2014/12/27/on-immigration-engineers-simply-dont-trust-vcs/"},{"by":"sanxiyn","id":8802425,"kids":[8805417,8802961,8803240],"score":116,"text":"","time":1419685288,"title":"Robdns \u2013 A fast DNS server based on C10M principles","type":"story","url":"https://github.com/robertdavidgraham/robdns"},{"by":"Petiver","id":8805487,"score":3,"text":"","time":1419747147,"title":"The Treasure of Nagyszentmiklós","type":"story","url":"http://en.wikipedia.org/wiki/Treasure_of_Nagyszentmikl%C3%B3s"},{"by":"carljoseph","id":8802485,"kids":[8803927,8805337,8803869,8803739,8804304,8804966,8804031,8803901,8804886,8803763,8805515,8803577,8804668,8804224],"score":76,"text":"","time":1419687337,"title":"The Software Scientist","type":"story","url":"http://www.evanmiller.org/the-software-scientist.html"},{"by":"Vigier","id":8804752,"score":7,"text":"","time":1419730398,"title":"House Perfect: Is the Ikea Ethos Comfy or Creepy? (2011)","type":"story","url":"http://www.newyorker.com/magazine/2011/10/03/house-perfect"},{"by":"sethbannon","id":8803844,"kids":[8805605,8805100,8804211,8804986,8804727,8804055,8804361,8805340,8804301,8804680,8804268,8804225,8804058,8804305,8804379],"score":59,"text":"","time":1419712871,"title":"When you have to wake up earlier than usual","type":"story","url":"http://blog.42floors.com/waking-up-early/"},{"by":"wslh","id":8804979,"score":5,"text":"","time":1419735352,"title":"How movies embraced Hinduism","type":"story","url":"http://www.theguardian.com/film/2014/dec/25/movies-embraced-hinduism"},{"by":"aestetix","id":8802138,"kids":[8802393,8802343,8802215,8802437,8802493,8803188,8802357,8804415,8802383,8802319,8802397,8803608,8802610,8802286,8802197,8802329,8802285,8802271,8802330],"score":157,"text":"","time":1419671428,"title":"31C3 Streaming: Saal 1 \u2013 SD Video","type":"story","url":"http://streaming.media.ccc.de/saal1/"},{"by":"diafygi","id":8803118,"kids":[8803351,8804151,8803613,8803234,8803409,8803466,8803454,8803396,8803395,8803413,8803381,8803427,8803926,8803416,8803369,8803587,8803402,8803974,8804261,8804322,8804245,8803140,8803340,8803424,8803897,8803357,8803363,8804917],"score":241,"text":"","time":1419700057,"title":"Many Android bugs with 500+ stars closed as obsolete on December 25","type":"story","url":"https://code.google.com/p/android/issues/list?can=1&q=status:Obsolete&sort=-stars"},{"by":"mrry","id":8802392,"kids":[8802474],"score":98,"text":"","time":1419684021,"title":"Functional Operating System and Security Protocol Engineering","type":"story","url":"http://decks.openmirage.org/31c3#/"}] 8 | 9 | ReactDOM.render(<NewsList items={items}/>, document.querySelector('#content')); 10 | 11 | 12 | //////////////////////////////////////////////////// 13 | // https://hacker-news.firebaseio.com/v0/item/22 14 | 15 | /* ---- comment ---- */ 16 | // { 17 | // by: "someone" 18 | // id: 22 19 | // kids: { 0: 33, 1: 44 } 20 | // parent: 11 21 | // text: "something something" 22 | // time: 1419743043 23 | // type: "comment" 24 | // } 25 | 26 | //////////////////////////////////////////////////// 27 | // https://hacker-news.firebaseio.com/v0/item/11 28 | /* ----- post ----- */ 29 | // { 30 | // by: "someone" 31 | // descendants: 200 32 | // id: 11 33 | // kids: { 0: 22, 1: 33, 3: 44 } 34 | // score: 999 35 | // time: 1419737448 36 | // title: "something something" 37 | // type: "story" 38 | // url: "http://example.com" 39 | // } 40 | -------------------------------------------------------------------------------- /part-2/b.kata/react-hn/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var config = { 4 | entry: path.resolve(__dirname, 'src/app.js'), 5 | output: { 6 | path: path.resolve(__dirname, 'build/js'), 7 | filename: "app.js", 8 | publicPath: "/js/" 9 | }, 10 | module: { 11 | loaders: [{ 12 | test: /\.jsx?$/, 13 | loader: 'babel', 14 | query: { 15 | presets: ['es2015', 'react'] 16 | } 17 | }] 18 | } 19 | }; 20 | 21 | 22 | module.exports = config; -------------------------------------------------------------------------------- /part-2/b.kata/readme.md: -------------------------------------------------------------------------------- 1 | search for the string `#componentkata` starting here on down 2 | 3 | ### getting started 4 | 5 | ``` 6 | # install the dependencies 7 | npm install 8 | 9 | # start the server 10 | npm run hot 11 | ``` -------------------------------------------------------------------------------- /part-2/c.communicate/build/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | <head> 4 | <title>8 Ways to Communicate 5 | 6 | 7 | 8 |
    9 | if you can see this then React isn't running yet 10 |
    11 | 12 | -------------------------------------------------------------------------------- /part-2/c.communicate/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "component-communication", 3 | "version": "0.0.1", 4 | "description": "learning about 8 ways to communicate among React components", 5 | "author": "Sherif Abushadi", 6 | "homepage": "https://github.com/amgando/react-workshop", 7 | "dependencies": { 8 | "react": "^0.14.7", 9 | "react-dom": "^0.14.7", 10 | "webpack-dev-server": "^1.14.0" 11 | }, 12 | "devDependencies": { 13 | "babel-core": "^6.5.2", 14 | "babel-loader": "^6.2.2", 15 | "babel-preset-es2015": "^6.5.0", 16 | "babel-preset-react": "^6.5.0", 17 | "webpack": "^1.12.1" 18 | }, 19 | "scripts": { 20 | "hot": "webpack-dev-server --content-base build/ --inline --hot", 21 | "start": "webpack-dev-server --content-base build/", 22 | "build": "webpack" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /part-2/c.communicate/readme.md: -------------------------------------------------------------------------------- 1 | ### getting started 2 | 3 | ``` 4 | # install the dependencies 5 | npm install 6 | 7 | # start the server 8 | npm run hot 9 | ``` 10 | 11 | ### references / inspiration 12 | 13 | 8 no-Flux strategies for React component communication 14 | http://andrewhfarmer.com/component-communication/ 15 | 16 | -------------------------------------------------------------------------------- /part-2/c.communicate/src/Props.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | const Props = (props) =>
    a message from above ... {props.p1} {props.p2} {props.p3}
    5 | 6 | export default Props -------------------------------------------------------------------------------- /part-2/c.communicate/src/main.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | import Props from './Props' 5 | 6 | class Communication extends React.Component { 7 | render(){ 8 | return
    9 | 10 |
    11 | } 12 | } 13 | 14 | ReactDOM.render(, document.querySelector('#container')) -------------------------------------------------------------------------------- /part-2/c.communicate/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | var config = { 4 | entry: path.resolve(__dirname, 'src/main.js'), 5 | output: { 6 | path: path.resolve(__dirname, 'build'), 7 | filename: "main.js", 8 | publicPath: "/" 9 | }, 10 | module: { 11 | loaders: [{ 12 | test: /\.jsx?$/, 13 | loader: 'babel', 14 | query: { 15 | presets: ['es2015', 'react'] 16 | } 17 | }] 18 | } 19 | }; 20 | 21 | module.exports = config; -------------------------------------------------------------------------------- /part-2/readme.md: -------------------------------------------------------------------------------- 1 | ## Developer Week :: React Workshop 2 | 3 | > delivered Wednesday, Feb 17, 2016 4 | > based on React 0.14 5 | > created by Sherif Abushadi (sherif@devbootcamp.com) 6 | 7 | --- 8 | 9 | ### timing 10 | - 10 am - 10:50 am 11 | 12 | 13 | ### slides 14 | 15 | [slides are here](https://docs.google.com/presentation/d/1ttAyxWIooMqY4tTHqlqTMk9dnhP4fWD-j7dmJwVQDvI/edit?usp=sharing) 16 | 17 | 18 | ### outcomes 19 | - you will be able to explain what React is and how it might have a place in your web application development story 20 | - you will be able to read and understand the majority of React-specific source code of any web application that uses React 21 | - you will be able to create your own custom components using several syntactic variants with ES5 and ES6 22 | - **you will be able to install and configure modern build tools for rapid development** 23 | - **you will be able to discover and reuse publicly available React components in your own application** 24 | - **you will be able to use the React Developer Tools to observe and modify component behavior in real time** 25 | 26 | 27 | 28 | ### part 2: development 29 | 30 | - [10 mins] we open with a look at the importance of build tools including setting up webpack's hot module replacement to speed up your development experience 31 | - [10 mins] next, with your build process optimized, we invite you to sink smiling into the blissful world of "component kata" 32 | - [30 mins] finally, we practice building components using a well structured approach: [8-ways to communicate among components](http://andrewhfarmer.com/component-communication/) using only React and JavaScript 33 | 34 | 35 | ### getting started 36 | 37 | ``` 38 | # install the dependencies 39 | npm install 40 | 41 | # start the server 42 | npm run hot 43 | ``` 44 | -------------------------------------------------------------------------------- /part-3/a.upgrade/readme.md: -------------------------------------------------------------------------------- 1 | the challenge here is to take an existing repo that's only a year old and bringing it to the current standard of React features, idioms and appropriate style. 2 | 3 | part of this is getting it up to speed with modern build tools. 2015 brought a feast of JavaScript build tools with popular community preferences seeming to change every few months. note that the repo included here is a year old and is not using npm and Webpack the way we did in the rest of this workshop. 4 | 5 | > hint: try reusing `package.json` and `webpack.config.js` 6 | 7 | also note that most of the code here is much harder to read than the previous version of this demo that you saw in "component kata" earlier. that one was rewritten to make things a little cleaner for you. try to do the same now with this code. 8 | 9 | 10 | **consider these resources**: 11 | 12 | - [Airbnb React/JSX Style Guide](https://github.com/airbnb/javascript/tree/master/react) 13 | - [Facebook's take on "Reusable Components"](https://facebook.github.io/react/docs/reusable-components.html) 14 | -------------------------------------------------------------------------------- /part-3/b.starter-kits/readme.md: -------------------------------------------------------------------------------- 1 | starter kits are a great way to save time on getting setup on a new project. they're also a bit of a nightmare to work with if you haven't spent enough time digging through them to build up an intuitive sense of what's missing in terms of package versioning, configuration settings and variations on those settings, complementary tools, configuration gotchas, etc. 2 | 3 | the hardest part is that as developers we don't spend much of our time doing this to begin with -- it's usually an investment we make at the beginning of a project or if something isn't working for us during our dev cycle. 4 | 5 | with that, have a look through at least 5 of these starter kits collected by Andrew Farmer here: http://andrewhfarmer.com/starter-project 6 | 7 | you can filter them number of stars, number of dependencies and recent activity. 8 | 9 | I recommend you filter them by "least dependencies" first and avoid digging into any starter kits that claim to get you up and running with 12 different technologies at the outset. in other words, it helps to learn to walk before we run. 10 | 11 | if you find a good starter kit, ie. one that seems understandable, behaves in a predictable way and actually gets some useful work done, then fork it. it's always a net positive: reducing the time from "wanting to code" to "actually coding" once the mood strikes. 12 | -------------------------------------------------------------------------------- /part-3/readme.md: -------------------------------------------------------------------------------- 1 | ## Developer Week :: React Workshop 2 | 3 | > delivered Wednesday, Feb 17, 2016 4 | > based on React 0.14 5 | > created by Sherif Abushadi (sherif@devbootcamp.com) 6 | 7 | --- 8 | 9 | ### timing 10 | - 11 am - 11:50 am 11 | 12 | 13 | ### slides 14 | 15 | [slides are here](https://docs.google.com/presentation/d/1ttAyxWIooMqY4tTHqlqTMk9dnhP4fWD-j7dmJwVQDvI/edit?usp=sharing) 16 | 17 | 18 | ### outcomes 19 | - you will be able to explain what React is and how it might have a place in your web application development story 20 | - you will be able to read and understand the majority of React-specific source code of any web application that uses React 21 | - you will be able to create your own custom components using several syntactic variants with ES5 and ES6 22 | - you will be able to discover and reuse publicly available React components in your own application 23 | - you will be able to use the React Developer Tools to observe and modify component behavior in real time 24 | - **you will be able to modify an existing React application to suit your needs** 25 | - **you will be able to incrementally introduce React to a static web application** 26 | 27 | 28 | ### part 3: maintenance 29 | 30 | - [10 mins] we end with an existing React application, one that we've seen before, and upgrade it from ES5 to ES6 31 | - [20 mins] next, choose a starter-kit, any starter-kit, and make it work 32 | - [20 mins] finally, start working on your own idea 33 | 34 | 35 | ### getting started 36 | 37 | ``` 38 | # install the dependencies 39 | npm install 40 | 41 | # start the server 42 | npm run hot 43 | ``` 44 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Developer Week :: React Workshop 2 | 3 | > delivered Wednesday, Feb 17, 2016 4 | > based on React 0.14 5 | > created by Sherif Abushadi (sherif@devbootcamp.com) 6 | 7 | --- 8 | 9 | ### timing 10 | - 9 am - 12 pm 11 | - 3 x 50 min segments with 10 min breaks after each 12 | - hands-on, bring your laptop 13 | 14 | 15 | ### slides 16 | 17 | [slides are here](https://docs.google.com/presentation/d/1ttAyxWIooMqY4tTHqlqTMk9dnhP4fWD-j7dmJwVQDvI/edit?usp=sharing) 18 | 19 | 20 | ### outcomes 21 | - you will be able to explain what React is and how it might have a place in your web application development story 22 | - you will be able to read and understand the majority of React-specific source code of any web application that uses React 23 | - you will be able to create your own custom components using several syntactic variants with ES5 and ES6 24 | - you will be able to install and configure modern build tools for rapid development 25 | - you will be able to discover and reuse publicly available React components in your own application 26 | - you will be able to use the React Developer Tools to observe and modify component behavior in real time 27 | - you will be able to modify an existing React application to suit your needs 28 | - you will be able to incrementally introduce React to a static web application 29 | 30 | 31 | ### what's not included? 32 | - anything about flux and [related implementations](https://github.com/voronianski/flux-comparison) (ie. alt, redux, etc.) 33 | - anything about fundamental system setup (we assume you have npm installed and running) 34 | - anything about cats because they already get enough attention as it is 35 | 36 | 37 | ### structure 38 | - **part 1**: orientation 39 | - [10 mins] we begin with a brief overview of what React is exactly, the kinds of problems it was intended to solve and why so many experienced developers like it 40 | - [20 mins] next we take a look at the common patterns of creating, connecting and organizing React components including `React.createClass()`, extending `React.Component` and creating pure components using JavaScript functions 41 | - [20 mins] finally, you get to build your first React components using one of our ideas or your own as a target for development 42 | 43 | - **part 2**: development 44 | - [10 mins] we open with a look at the importance of build tools including setting up webpack's hot module replacement to speed up your development experience 45 | - [10 mins] next, with your build process optimized, we invite you to sink smiling into the blissful world of "component kata" 46 | - [30 mins] finally, we practice building components using a well structured approach: [8-ways to communicate among components](http://andrewhfarmer.com/component-communication/) using only React and JavaScript 47 | 48 | - **part 3**: maintenance 49 | - [10 mins] we end with an existing React application, one that we've seen before, and upgrade it from ES5 to ES6 50 | - [20 mins] next, choose a starter-kit, any starter-kit, and make it work 51 | - [20 mins] finally, start working on your own idea 52 | 53 | 54 | ### installation 55 | 56 | This repository has everything you need to get started so just 57 | ```bash 58 | # clone the repo 59 | git clone https://github.com/amgando/react-workshop.git 60 | 61 | # cd into the folder 62 | cd react-workshop 63 | 64 | # follow the readme.md directions per folder 65 | 66 | # typically that will just be running the following commands 67 | # for installing dependencies 68 | npm install 69 | 70 | # and to start the server, either "HMR mode" or "regular mode" 71 | npm run hot 72 | #-or-# 73 | npm start 74 | ``` 75 | 76 | *If for some reason you aren't able to run `npm`, the limited time in this workshop won't allow for us to troubleshoot your computer. Instead, we have an online version available for you to use so you can keep up with the workshop without having to configure your machine.* 77 | 78 | 79 | --------------------------------------------------------------------------------