Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting into React

Getting into React

Intro presentation on React:

Have you ever wanted to try out React? It's a great library to help you build UIs for your single page apps. Together we'll walk through the basics of this great tool, looking at its component abstraction, how it helps you manage state, and how it will simplify your approach to UI development. We'll give you a feel for what a real React project is like, touching on all the pieces you'll need to try it out yourself. In the end, you'll have a better idea for what React is good for and how you can pick it up to help you on your next project.

Read more on React at jaketrent.com

#reactjs

510e0501c737af4df361f945fc295f63?s=128

Jake Trent

May 19, 2017
Tweet

Transcript

  1. REACT GETTING INTO JAKE TRENT

  2. None
  3. None
  4. REACT IS A: npm install react ▸ Let the fun

    begin! UI LIBRARY
  5. INSIDE A: COMPONENT

  6. UI ABSTRACTION: COMPONENTS ▸ Exposes a React.Component import React from

    ‘react’
  7. COMPONENTS OUTPUT: VIEW ▸ Matches the DOM <div> <span>For your

    eyes only</span> </div>
  8. REACT APPROACH VIEW ONLY ▸ Just a view ▸ Just

    a library ▸ Bring your own: app framework, client router, http library, module system, service layer, model library
  9. CUSTOM COMPONENTS: ▸ Semantic naming <SideNav> <Logo /> </SideNav> ▸

    Capitalized == custom ▸ Composable hierarchy
  10. REACT COMPONENTS ARE: ▸ Return DOM function SideNav() { return

    <div>...</div> } JUST FUNCTIONS
  11. REACT APPROACH SEPARATION OF CONCERNS ▸ Not technology ▸ Uses

    JSX (superset of JS) ▸ Include what looks like HTML in your functions function SideNav() { return <div>...</div> }
  12. COMPONENT STATE: PROPS ▸ Immutable bag of data ▸ Flow

    into component from parent function SideNav(props) { return <div>{props.links}</div> } ▸ Allow dynamic output ▸ Like arguments to a function
  13. JSX NOTE: CURLIES <div>{props.links}</div> ▸ Switch back to JS from

    HTML ▸ Inside curlies interpreted as {plain JS}
  14. COMPONENT STATE: PASS PROPS <SideNav links={[‘home’, ‘about’]} /> ▸ Like

    attributes in HTML
  15. TWO STYLES: COMPONENT SYNTAX ▸ Function style (aka “stateless components”)

    import React from ‘react’ class MyComponent extends React.Component {} ▸ Class style import React from ‘react’ function MyComponent() {}
  16. COMPONENT STATE: THIS.STATE ▸ Internal to component ▸ Mutable ▸

    Requires class-style components
  17. STATE INITIALIZATION: THIS.STATE import React from ‘react’ class Counter extends

    React.Component { constructor(props) { super(props) this.state = { count: 0 } } }
  18. STATE UPDATING: THIS.SETSTATE import React from ‘react’ class Counter extends

    React.Component { handleCountUpdate() { this.setState({ count: this.state.count + 1 }) } } ▸ (the mutating)
  19. COMPONENT: RENDERING

  20. COMPONENT CLASS: RENDERING import React from ‘react’ class SideNav extends

    React.Component { render() { return <div>{this.props.links}</div> } } ▸ Note `this.props.links` vs. `props.links` ▸ Must implement `render`
  21. COMPONENTS RENDER: VIRTUAL DOM import React from ‘react’ class SideNav

    extends React.Component { render() { return <div>{this.props.links}</div> } } ▸ Return DOM… Virtual DOM
  22. VIRTUAL DOM: ▸ In-memory representation ▸ Handled by React ▸

    Manages changes, dirty checking ▸ Auto updates the real DOM Real DOM Virtual DOM React-managed Browser-managed
  23. JSX TRANSFORMED INTO: FUNCTION CALLS <div>{props.links}</div> ▸ Before React.createElement(‘div’, props.links)

    ▸ After
  24. IN-MEMORY: DOM REPRESENTATION { '$$typeof': Symbol(react.element), type: 'div', key: null,

    ref: null, props: { '0': 'home', '1': 'about' }, _owner: null, _store: {} } ▸ Output of `React.createElement`
  25. REACT APPROACH NO TEMPLATE LANGUAGE ▸ JSX small differences vs.

    HTML: ▸ camelCase attributes - e.g., `onClick` (except aria-* & html-*) ▸ html* prefix - e.g., `htmlFor` ▸ alternate words - e.g., `className` ▸ Curlies revert back to {JS}
  26. CONNECT REACT TO: REAL DOM npm install react-dom import {

    render } from ‘react-dom’ render(<MyAppComponent />, document.getElementById(‘app’)) ▸ Call it once ▸ React handles translating VDOM to DOM
  27. REACT APPROACH LEARN ONCE, WRITE ANYWHERE ▸ Multiple render targets

    ▸ react-dom ▸ react-dom/server ▸ react-native
  28. INSERTED INTO DOM: “MOUNT” ▸ When your component is inserted

    into the real DOM ▸ 1. Created in memory ▸ 2. ReactDOM.render ▸ 3. Mount ▸ 4. Eventual removal called “unmount”
  29. in DOM / visible COMPONENT MOUNT: Mount Unmount constructor componentWillMount

    componentDidMount componentWillUnmount ▸ ▸ ▸ ▸ ▸ LIFECYCLE HOOKS time ▸
  30. ACCESS TO DOM: REF class UsernameField extends React.Component { render()

    { return <input ref={el => this.input = el} /> } }
  31. ACCESS TO DOM: DID MOUNT class UsernameField extends React.Component {

    componentDidMount() { this.input.focus() } render() { return <input ref={i => this.input = i} /> } }
  32. HANDLING: EVENTS <input onChange={this.handleChange} /> ▸ camelCase attributes ▸ eg,

    `onClick`, `onSubmit`, `onChange`, … handleChange(evt) { this.setState({ username: evt.target.value }) }
  33. EVENT GOTCHA: CALLBACK BINDING constructor(props) { super(props) this.handleChange = this.handleChange.bind(this)

    } handleChange(evt) { this.setState({ username: evt.target.value }) } ▸ bind to component context in constructor
  34. REAL: COMPONENT class UsernameField extends React.Component { constructor() {…} componentDidMount()

    {…} handleChange() {…} render() {…} }
  35. REAL: COMPONENT class UsernameField extends React.Component { constructor(props) { super(props)

    this.state = { username: ‘’ } this.handleChange = this.handleChange.bind(this) } componentDidMount() {…} handleChange() {…} render() {…} }
  36. REAL: COMPONENT class UsernameField extends React.Component { constructor() {…} componentDidMount()

    {…} handleChange() {…} render() { return <label htmlFor=“user”> {this.props.label} <input id=“user” ref={el => this.input = el} onChange={this.handleChange} /> </label> } }
  37. REAL: COMPONENT class UsernameField extends React.Component { constructor() {…} componentDidMount()

    { this.input.focus() } handleChange() {…} render() {…} }
  38. REAL: COMPONENT class UsernameField extends React.Component { constructor() {…} componentDidMount()

    {…} handleChange(evt) { this.setState({ username: evt.target.value }) } render() {…} }
  39. REAL: COMPONENT class UsernameField extends React.Component { constructor(props) { super(props)

    this.state = { username: ‘’ } this.handleChange = this.handleChange.bind(this) } componentDidMount() { this.input.focus() } handleChange(evt) { this.setState({ username: evt.target.value }) } render() { return <label htmlFor=“user”> {this.props.label} <input id=“user” ref={el => this.input = el} onChange={this.handleChange} /> </label> } }
  40. MULTIPLE: COMPONENTS

  41. SHARING: DATA ▸ Lift to common parent ▸ Pass to

    children as `props` LoginForm UsernameField PasswordField
  42. SHARING: DATA LoginForm UsernameField PasswordField this.state = { username: ‘’

    password: ‘’ } <form> <UsernameField value={this.state.username} /> <PasswordField value={this.state.password} /> </form> <input value={props.value} /> <input value={props.value} /> ▸ Data flows down
  43. NOTIFYING: CHANGE ▸ Communicating change to parent ▸ Via callback

    functions LoginForm UsernameField PasswordField
  44. NOTIFYING: CHANGE LoginForm UsernameField PasswordField handleChange(evt) { this.setState({ [evt.target.name]: evt.target.value

    }) } <form> <UsernameField onChange={this.handleChange} value={this.state.username} /> <PasswordField onChange={this.handleChange} value={this.state.password} /> </form> <input name=“username” onChange={props.onChange} /> <input name=“password” onChange={props.onChange} /> ▸ Changes notify up
  45. REACT APPROACH EXPLICIT FLOW ▸ Strict conventions ▸ props ▸

    callbacks ▸ No automatic binding ▸ Explicit plumbing
  46. RENDERING: CHANGES ▸ Re-render triggered by changes to: ▸ this.props

    ▸ this.state ▸ Re-render self and children
  47. RENDERING: CHANGES LoginForm UsernameField ▸ Example: User types username

  48. RENDERING: CHANGES LoginForm UsernameField User types, triggers props.onChange

  49. RENDERING: CHANGES LoginForm UsernameField props.onChange calls back to parent

  50. RENDERING: CHANGES LoginForm UsernameField this.handleChange called, this.setState() w/ new value

  51. RENDERING: CHANGES LoginForm UsernameField this.state change, triggers call to render()

  52. RENDERING: CHANGES LoginForm UsernameField passes new prop w/ this.state.username value

  53. RENDERING: CHANGES LoginForm UsernameField New prop triggers render(), value displayed

    onscreen ▸ React takes care of all DOM updates
  54. CALL RENDER: ONCE ▸ React takes care of all DOM

    updates ▸ No bit twiddling import { render } from ‘react-dom’ render(<LoginForm />, document.getElementById(‘app’))
  55. REACT APPROACH REPAINT EVERYTHING ▸ Declare UI based on state

    ▸ Pass to React as a whole to repaint everything ▸ Simple dev mental model
  56. REACT APPROACH REPAINT EVERYTHING ▸ Top-down render ▸ Frame by

    frame, like game programming ReactDOM.render(<TopComponent />)
  57. CONTROLLING: REPAINT ▸ State change causes repaint / update ▸

    Default behavior: `this.state` or `props` change ▸ Can change that behavior
  58. COMPONENT UPDATE: Update LIFECYCLE HOOKS time ▸ componentWillReceiveProps shouldComponentUpdate componentWillUpdate

    render ▸ ▸ ▸ ▸ ▸ componentDidUpdate
  59. COMPONENT: DESIGN

  60. EXTRACTING: COMMONALITY ▸ Reuse, maintainability, consistency UsernameField PasswordField LoginField

  61. EXTRACTING: COMMONALITY const UsernameField = props => <label htmlFor=“user”> {props.label}

    <input id=“user” name=“username”
 onChange={props.onChange} /> </label> ▸ Start with similar, duplicated components: ▸ (and a similar PasswordField component)
  62. EXTRACTING: COMMONALITY const LoginField = props => <label htmlFor={props.name}> {props.label}

    <input id={props.name} name={props.name} onChange={props.onChange} type={props.type || ‘text’} /> </label> ▸ Create a common, generalized component:
  63. EXTRACTING: COMMONALITY const UsernameField = props => <LoginField label={props.label} name=“username”

    onChange={props.onChange} /> const PasswordField = props => <LoginField label={props.label} name=“password” onChange={props.onChange} type=“password” /> ▸ Wrapped in two specific components:
  64. REACT APPROACH COMPOSITION ▸ Polymorphism via composition ▸ No inheritance

    ▸ Component wrapping is common
  65. DOCUMENTING: FOR THE FUTURE npm install prop-types ▸ Discoverability, learning,

    correct usage ▸ Good citizen ▸ Describing the public interface (props)
  66. DOCUMENTING: FOR THE FUTURE import PropTypes from ‘prop-types’ LoginField.propTypes =

    { label: PropTypes.string, name: PropTypes.string.isRequired, onChange: PropTypes.func.isRequired, type: PropTypes.string } ▸ List all props
  67. DOCUMENTING: FOR THE FUTURE <LoginField name=“username” /> ▸ At dev

    time, if misuse prop, get warning Warning: Failed prop type: The prop `onChange` is marked as required in `LoginField`, but its value is `undefined`.
  68. PROVIDING: DEFAULTS LoginField.defaultProps = { type: ‘text’ } ▸ When

    specific props aren’t sent ▸ Use these values
  69. REACT: IN A PROJECT

  70. PROJECT: SETUP npm install create-react-app --global ▸ No-config setup tool

  71. PROJECT: SETUP create-react-app my-app cd my-app/ npm start open localhost:3000

  72. PROJECT: SETUP

  73. PROJECT: SETUP import React, { Component } from 'react'; import

    logo from './logo.svg'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <div className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h2>Welcome to React</h2> </div> <p className="App-intro"> To get started, edit <code>src/App.js</code> and save to reload. </p> </div> ); } } export default App;
  74. PROJECT: BUILD ▸ Webpack-based ▸ Everything’s a module ▸ Webpack

    is powerful ▸ Complicated, and worth learning import './App.css'
  75. COMPONENT: STYLING ▸ Many options ▸ Influenced by React community

    portable, isolated, rebel external, cascade, traditional Inline Stylesheet
  76. REACT APPROACH RETHINK BEST PRACTICES ▸ eg, inline styles ▸

    or repaint “everything” on update?!
  77. COMPONENT: STYLING portable, isolated, rebel external, cascade, traditional CSS Modules

    Inline Stylesheet isolated, dependencies, composition
  78. CSS MODULES: ISOLATED ▸ CSS exposed in export object ▸

    Use original selector in code import css from ‘./index.css’ <div className={css.mySelector} />
  79. CSS MODULES: ISOLATED ▸ Value of selector name in export

    object is hashed <div class=“mySelector__4ef12” /> ▸ Making them unique in global namespace ▸ Changes isolated to component my-component.js my-component.css <div className={css.mySelector} />
  80. CSS MODULES: EXPLICIT DEPENDENCIES @import “./common.css”; .mySelector { composes: commonSelector;

    color: red; } class=“mySelector__4ef12 commonSelector__ab5tc”
  81. COMPONENT: TESTING npm install jest --save-dev test(‘basic assertion’, () =>

    { expect(true).toEqual(true) }) ▸ Built on Jasmine ▸ Helpful with mocking ▸ Snapshot testing
  82. SNAPSHOT: TESTING test(‘render correctly’, () => { const tree =

    renderer.create(<MyComponent />) expect(tree).toMatchSnapshot() }) ▸ Similar to taking a screenshot ▸ Comparing changes against original screenshot ▸ But “screenshot” is just a text serialization
  83. CLIENT-SIDE: ROUTER ▸ Many options: ▸ react-router ▸ page.js <Router>

    <Route path=“/login” component={LoginPage} /> </Router> npm install react-router-dom
  84. PROJECT: LAYOUT ▸ Instead of by tiers "## controllers "##

    db "## models "## services $## view "## alerts "## game "## home $## login ▸ By features
  85. PROJECT: LAYOUT ▸ Tests next to src login "## __specs__

    % "## index.spec.js % $## validators.spec.js "## index.css "## index.js "## sub-component.css "## sub-component.js $## validators.js
  86. STATE MANAGEMENT: ▸ Based on Flux pattern ▸ A pattern

    to help you organize app state ▸ Will complicate your app ▸ If benefit > complexity, do it ▸ Use `props` and `this.state` otherwise REDUX
  87. REACT PROJECT: COMPLEXITY React Build toolchain Large project organization Routing

    Sharing app state ▸ Around the edges Data
  88. REACT PROJECT: COMPLEXITY React Routing Data ▸ Component-based ▸ Small

    to mid-sized ▸ = Joy
  89. REACT IN THE: LARGE ▸ Still the best experience I’ve

    had ▸ Abstractions scale well ▸ Redux implements a solid pattern at scale
  90. INTRODUCE REACT: GRADUALLY <div> My Other-Framework app <div id=“small-piece”></div> </div>

    ReactDOM.render(<LoginForm />, document.getElementById(‘small-piece’)) ▸ Just need a DOM element to own
  91. COMPONENTS ARE FOR: SHARING ▸ Great encapsulation ▸ Simple public

    API ▸ Built-in documentation ▸ Productive community npm publish
  92. FIND SUPPORT: IN THE COMMUNITY ▸ Questions: ▸ StackOverflow #reactjs

    ▸ Forum: discuss.reactjs.org ▸ Chat: “reactiflux” discord, #reactjs IRC ▸ OSS: github.com/reactjs ▸ Docs: facebook.github.io/react
  93. FINISH: YOUR TRAINING ▸ Pluralsight.com ▸ Egghead.io ▸ ReactTraining.com ▸

    there.. is.. another..
  94. A COUPLE: EXAMPLE PROJECTS github.com/jaketrent/wordspies ▸ React + Redux +

    more: github.com/jaketrent/mastermind-saga ▸ Just React: ▸ (Disregard server portions)
  95. USE: WHAT YOU KNOW ▸ You know: ▸ How components

    work ▸ The React approach ▸ How to start a project ▸
  96. THANK YOU JAKETRENT.COM