class: center, middle, inverse # React + redux Elevate 14 april 2016 --- # whoarewe ### John - JavaScript developer - [@johnste](https://github.com/johnste) on github - Using React and Redux since late 2015 ### Pontus - Frontend/JavaScript developer - [@hontas](https://github.com/hontas) on github - Reacter since summer 2015 --- # whoareyou - JavaScript? - ES6? - Frontend? - React? --- # Agenda -- count: false ### - Basic ES6 (ES2015) -- count: false ### - React Fundamentals -- count: false ### - Redux -- count: false ### - Example App -- count: false ### - AW đ» --- class: center, middle, inverse # ES6 --- # ES6 - let/const *proudly presented in block scope* ```javascript if (true) { let a = 5; } a += 4; // ReferenceError: a is not defined const x = 5; x = 6; // TypeError ``` --- # ES6 - Arrow Functions ES5 ```javascript this.count = 0; var that = this; setInterval(function() { that.count++; }, 1000); ``` ??? - Lexical `this` - Closest `this` applies -- count: false ES6 ```javascript this.count = 0; setInterval(() => { this.count++; }, 1000); ``` --- # ES6 - Template Literals ```javascript const a = 1; const b = 3; const kindOf = "multiline"; const message = `Hey, this is a ${kindOf} string. ${a + b}.`; // Hey, this is a multiline string. // 3. ``` ??? - Multiline - Interpolation --- # ES6 - Default Parameters ES5 ```javascript function sayHello(name) { name = name || 'Jontus Doe'; return 'Hello ' + name + '.'; } ``` -- count: false ES6 ```javascript function sayHello(name = 'Johntus Doe') { return `Hello ${name}.`; } ``` ```javascript > sayHello() // "Hello Johntus Doe. ``` --- # ES6 - Object Literal Shorthand & Computed Properties ES5 ```javascript var url = 'http://...'; var key = 'a key'; var api = { url: url, putJSON: function () { ... }, }; // Have to assign key after api[key] = 'a value'; ``` -- count: false ES6 ```javascript const url = 'http://...'; const api = { url, putJson() { ... }, [key]: 'a value' }; ``` --- # ES6 - Destructuring ES5 ```javascript var point = getPoint(); var x = point.x; var y = point.y; ``` -- count: false ES6 ```javascript const { x, y } = getPoint(); ``` --- # ES6 - Object Rest/Spread ES5 ```javascript function sum() { return [].slice.call(arguments) .reduce((sum, curr) => sum + curr); } var obj = { a: '1', b: '2' }; var obj2 = Object.assign({}, obj, { c: '3' }); ``` -- count: false ES6 ```javascript function countArgs(...args) { return args.reduce((sum, curr) => sum + curr); } const obj = { a: '1', b: '2' }; const obj2 = { ...obj, c: '3' }; ``` --- # ES6 - Classes ```javascript class Point { constructor(x, y) { this.x = x; this.y = y; } } ``` ??? - syntactic sugar - composition over inheritence --- # ES6 - Modules ES6 ```javascript // exporting export const PropTypes = {}; export default function React() {}; // importing import React, { PropTypes } from 'react'; ``` ??? - Statically analyzed (for static checking, optimization, etc.). - Support for cyclic dependencies is better than CommonJSâs - Programmatic loader API: to configure how modules are loaded and to conditionally load modules - Tree shaking --- class: center, middle, inverse # React The V in MVC --- # React ### Prior Art - ***Ember*** - full MVC - ***Angular*** - everything and a kitchen sink What problems is it solving? [DOM manipulation comparison](https://www.youtube.com/watch?v=z5e7kWSHWTg) ??? - DOM is slow - only view layer - Komponentbaserat --- # React - JSX - superset of JS - opt in - paves the way for ES6+ ```javascript render() { return (
Email
Click me!
); } ``` ??? Att notera - `className` - `htmlFor` - `events` - `{ js here }` --- # React - Vanilla JS ```javascript render() { return ( React.createElement( "form", { className: "sign-in-form" }, React.createElement( "label", { htmlFor: "email" }, "Email" ), React.createElement("input", { type: "email", id: "email" }), React.createElement( "button", { onClick: this.onHandleClick }, "Click me!" ) ); ); } ``` --- # React - Hello world ```jsx // app.jsx import React from 'react'; import { render } from 'react-dom'; import HelloWorld from './helloWorld.jsx'; render(
, document.getElementById('container') ); ``` ```jsx // helloWorld.jsx import React from 'react'; export default () => { return
Hello, world!
; } ``` ??? - `import React from...` pga `React.createElement` --- # React - Component Stateful component ```jsx export default React.createClass({ getInitialState() { return { name: 'John' }; }, render() { return
Hello { this.state.name }
; } }); ``` ??? - access till lifecycle - internt state -- count: false Stateful component class ```jsx export default class MyComponent extends React.Component { constructor() { this.state = { name: 'John' }; } render() { return
Hello { this.state.name }
; } }); ``` --- # React - Component Stateless component ```javascript export default React.createClass({ render() { return
Hello { this.props.name }
; } }); ``` -- count: false Pure component ```javascript export default ({ name }) => { return
Hello { name }
; } ``` đđđ ??? - pure Ă€r efterstrĂ€vansvĂ€rd! --- # React - Component - State vs Props - Immutability - Pure state -> DOM - Automatic rerender ### Always be using props! -- count: false except... ```jsx export default InputField = React.createClass({ onChange(evt) { this.setState({ value: evt.target.value }); }, render() { return
} }); ``` --- # React - Component - Controller view ```javascript export default React.createClass({ getInitialState() { return { items: [], currentItemId: null }; }, render() { return (
); }, onFilter() {}, onSelectItem() {} }); ``` ??? - collect data in one view - provide data manipulation callbacks --- # React - Component - Lifecycle methods ```javascript export default React.createClass({ getInitialState() {}, getDefaultProps() {}, componentWillMount() {}, componentDidMount() {}, componentWillUnmount() {}, componentWillReceiveProps(nextProps) {}, shouldComponentUpdate(nextProps, nextState) {}, componentWillUpdate(nextProps, nextState) {}, componentDidUpdate(prevProps, prevState) {}, shouldComponentUpdate() {}, componentWillUpdate() {}, componentDidUpdate() {}, render() {} }); ``` ??? - initial state - mounting - component update - only stateful components - render method required - vilka Ă€r viktiga? --- class: center, middle, inverse # đ± + đŁ + đș? --- class: center, middle, inverse # Redux The M in MVC --- # Redux Can't not manage data - Backbone model - Flux --- # Redux - Flux to the resque! *Unidirectional data flow* ![flux](https://docs.google.com/drawings/d/1VGR2SCceyl22rUi92vqP1ttGcpBPmoBLGknCG7dMmL0/pub?w=959&h=357) ??? - en app dispatcher - data flödar Ă„t ett hĂ„ll --- # Redux - ~~Flux to the resque!~~ *Store hell & waitFor* ![flux](https://docs.google.com/drawings/d/1oNW3w6RdnLJna8wSE8T01moKMqD5XlQ024-Onukvs_g/pub?w=959&h=357) ??? - multiple stores - inter store dependancies - waitFor - utspritt state - addListener/removeListener - komponenten suger i sig state --- # Redux - Redux *Predictable state container* ![redux](https://docs.google.com/drawings/d/1_1CtFfIH7zqfNSO3Cl2mI7iYa5zAKodiuKY2JGIZfE0/pub?w=959&h=357) ??? - reducers jobbar pĂ„ delmĂ€ngder av globalt state - state pushas till vyn - vyer kan plocka ut delmĂ€ngd av globalt state --- # Redux - Redux *Easily reason about your data* ![redux](https://docs.google.com/drawings/d/1zn2arct1NehY0r2N5x5lnZ00-UWHLv0YrUPPSXBap-4/pub?w=959&h=357) ??? - scales well --- # Redux - Parts ### - Action creators ### - Reducers ### - Store --- # Redux - Action creators *Describe mutation intent* ```javascript export GET_CATS = 'get some cats'; export function getCats(catType) { return { type: GET_CATS, catType }; } ``` ...in some other file ```javascript store.dispatch(getCats('norsk bonnakatt')); ``` --- # Redux - Reducers *pure function mutation* ```javascript import { GET_CATS } from './actions'; export function catReducer(state = {}, action) { switch(action.type) { case GET_CATS: return { ...state, futureCatType: action.catType, isLoadingCats: true }; default: return state; } } ``` --- # Redux - Store ```javascript import { createStore, combineReducers } from 'redux'; import { catReducer } from '../reducers'; const initialState = {}; const rootReducer = combineReducers({ cats: catReducer }); const store = createStore( rootReducer, initialState ); export default store; ``` ```javascript store.dispatch() store.getState() ``` --- # Redux - Hello Redux ```javascript import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-redux'; import store from './store'; import Application from './application.jsx'; render(
, document.getElementById('container') ); ``` --- # Redux - Connected components Deeply nested state ```jsx
``` passthrough or...? --- # Redux - Connected components ```javascript import { getCats } from './actions'; const MyComponent = ({cats = [], dispatch}) => { function onClick() { dispatch(getCats()); } return (
{ cats.map(cat =>
{cat}
) }
Get some cats
); }; function mapStateToProps({ cats }) { return { cats: cats.allCats, isYourFavoriteCat: cats.futureCatType === 'norsk bonnkatt' }; } export default connect(mapStateToProps)(MyComponent); ``` --- class: center, middle, inverse # Example app Demo ??? - webpack - HMR - Compile errors in window - propType validation errors - CSS automatic update --- class: center, middle, inverse # Questions? --- # Links - [These slides](http://johnste.github.io/react-redux-presentation) - [Learn ES6](http://babeljs.io/docs/learn-es2015/) - [React + Webpack cookbook](http://survivejs.com/webpack/introduction/) - [Redux documentation](http://redux.js.org/docs/introduction/index.html) - [Getting started with redux video series](https://egghead.io/series/getting-started-with-redux) ### Further reading - [pokedex](http://www.pocketjavascript.com/blog/2015/11/23/introducing-pokedex-org) ### React alternatives - [preact](https://github.com/developit/preact) - [cycle.js](http://cycle.js.org/) - [elm](http://elm-lang.org/)