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

setState ftw

setState ftw

"Nobody knows how to do anything without Redux anymore. It's ridiculous." - @mjackson
Let's fix it!

Michele Bertoli

October 06, 2017
Tweet

More Decks by Michele Bertoli

Other Decks in Programming

Transcript

  1. setState ftw
    @MicheleBertoli

    View full-size slide

  2. My name’s Michele and I’m a React
    fanboy since 2014

    View full-size slide

  3. I work in Ads at Facebook, and I
    contribute to a pretty sophisticated
    React UI

    View full-size slide

  4. setState is the primary method you use
    to update the UI in React

    View full-size slide

  5. Are we really going to talk about
    setState for 40 minutes?

    View full-size slide

  6. “I’m learning React but I don’t
    understand reducers.”
    Anonymous, Mar 2017

    View full-size slide

  7. react-redux
    redux
    react
    react-router
    react-router-redux

    View full-size slide

  8. react-redux
    redux
    react
    react-router
    react-router-redux

    View full-size slide

  9. The community

    View full-size slide

  10. “Nobody knows how to do
    anything without Redux
    anymore. It's ridiculous.”
    @mjackson, Jun 2016

    View full-size slide

  11. “3 Reasons why I stopped
    using React.setState.”
    @mweststrate, Jun 2016

    View full-size slide

  12. “I love setState. In 3 1/2 years,
    I haven't needed anything
    more.”
    @chantastic, Mar 2017

    View full-size slide

  13. “You might not need Redux.”
    @dan_abramov, Sep 2016

    View full-size slide

  14. Common Pitfalls

    View full-size slide

  15. setState({ title: 'Here comes the sun' })
    console.log(this.state.title)

    View full-size slide

  16. setState is asynchronous

    View full-size slide

  17. setState({ counter: this.state.counter + 1 })
    setState({ counter: this.state.counter + 1 })

    View full-size slide

  18. Object.assign(
    prevState,
    { counter: this.state.counter + 1 },
    { counter: this.state.counter + 1 },
    )

    View full-size slide

  19. Multiple setState calls get batched

    View full-size slide

  20. this.state.title = 'Come together'

    View full-size slide

  21. Mutating the state is an anti-pattern

    View full-size slide

  22. this.state = {
    song: {
    title: 'Let it be',
    year: 1970,
    },
    }

    View full-size slide

  23. this.setState({
    song: {
    title: 'Hey Jude',
    },
    })

    View full-size slide

  24. State changes are shallow merged

    View full-size slide

  25. yarn add setstate
    - DON’T TRY THIS AT HOME -

    View full-size slide

  26. “If setState was packaged up
    as a lib, people would love it.”
    @chantastic, Jul 2017

    View full-size slide

  27. setState enqueues changes to the component state
    and tells React that a component and its children
    need to be re-rendered with the updated state.

    View full-size slide

  28. setState enqueues changes to the component state
    and tells React that a component and its children
    need to be re-rendered with the updated state.

    View full-size slide

  29. setState(updater, [callback])

    View full-size slide

  30. (prevState, props) => stateChange

    View full-size slide

  31. setState(stateChange, [callback])

    View full-size slide

  32. Best practices

    View full-size slide

  33. @dan_abramov, Jul 2016

    View full-size slide

  34. this.state = {
    price: `${props.currency}${props.value}`,
    }
    Don’t

    View full-size slide

  35. this.setState({
    request: API.get(...),
    })
    Don’t

    View full-size slide

  36. this.setState(
    (prevState, props) => ({
    counter: prevState.counter + props.step,
    })
    )

    View full-size slide

  37. export const increment =
    (prevState, props) => ({
    counter: prevState.counter + props.step,
    })

    View full-size slide

  38. import { increment } from './updaters'
    this.setState(increment)

    View full-size slide

  39. test('increment', () => {
    const prevState = { counter: 1 }
    const props = { step: 1 }
    expect(
    increment(prevState, props)
    ).toEqual({ counter: 2 })
    })

    View full-size slide

  40. test('increment', () => {
    const prevState = { counter: 1 }
    const props = { step: 1 }
    expect(
    increment(prevState, props)
    ).toMatchSnapshot()
    })

    View full-size slide

  41. Separation of concerns

    View full-size slide

  42. ● Container: data and behaviour
    ● Presentational: appearance
    Container and Presentational

    View full-size slide

  43. componentDidMount() {
    API.get(...).then(s => this.setState(s))
    }
    render() {
    return
    }

    View full-size slide

  44. cb() {
    API.post(...).then(s => this.setState(s))
    }
    render() {
    return
    }

    View full-size slide

  45. yarn add react-fetching

    View full-size slide

  46. url="https://api.punkapi.com/v2/beers"
    ok={beers => {beers[0].name}}
    />

    View full-size slide

  47. ● Higher-order components
    ● Component => Component
    ● Options => Component => Component
    Composition

    View full-size slide

  48. yarn add react-refetch

    View full-size slide

  49. connect(mapPropsToRequests)(Component)

    View full-size slide

  50. connect(() => ({
    f: 'https://api.punkapi.com/v2/beers'
    }))(
    ({ f }) => f.fulfilled
    ? {f.value[0].name}
    : null
    )

    View full-size slide

  51. Sharing state

    View full-size slide

  52. Do you even lift (your state up)?

    View full-size slide

  53. componentDidMount() {
    API.get(...).then(s => this.setState(s))
    }
    render() {
    return {this.state.data}
    }

    View full-size slide

  54. componentDidMount() {
    API.get(...).then(this.props.cb)
    }
    render() {
    return {this.props.data}
    }

    View full-size slide

  55. cb(data) {
    this.setState({ data })
    }
    render() {
    return
    }

    View full-size slide

  56. yarn add react-broadcast

    View full-size slide

  57. channel="state"
    value={this.state}
    >
    {this.props.children}

    View full-size slide


  58. {state => (
    {state.data}
    )}

    View full-size slide

  59. yarn add --dev react-lumberjack

    View full-size slide

  60. Lumberjack.back()
    Lumberjack.forward()

    View full-size slide

  61. dispatch(action) {
    this.setState(
    prevState => reducer(prevState, action)
    )
    }

    View full-size slide

  62. yarn add t-redux

    View full-size slide

  63. const reducer = buildReducer({
    'INCREMENT': state => ({
    counter: state.counter + 1,
    }),
    })
    const initialState = { counter: 0 }

    View full-size slide

  64. const inc = () => dispatcher.dispatch({
    type: 'INCREMENT',
    })
    const Button = ({ counter }) => (
    {counter}
    )

    View full-size slide

  65. withState([reducer], initialState)(Button)

    View full-size slide

  66. ● Best practices
    ● Testing
    ● Separation of concerns
    ● Sharing state
    ● Time Travel
    ● Functional
    Recap

    View full-size slide

  67. State Management

    View full-size slide

  68. ● Higher-order components
    ● Immutability
    ● Pure functions
    ● Generators
    ● Observables
    Requirements

    View full-size slide

  69. ● Make informed decisions about your tools
    ● Understand the tradeoffs involved in each
    decision
    Choose wisely

    View full-size slide

  70. ● react-redux uses setState
    ● mobx-react uses forceUpdate
    Know your tools

    View full-size slide

  71. Keep it simple

    View full-size slide

  72. Lift your state up

    View full-size slide

  73. Michele Bertoli
    Front End Engineer at Facebook
    Author of React Design Patterns and Best Practices
    Follow me @MicheleBertoli

    View full-size slide