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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  6. YES

    View Slide

  7. Ok, why?

    View Slide

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

    View Slide

  9. react

    View Slide

  10. react-redux
    redux
    react
    react-router
    react-router-redux

    View Slide

  11. react-redux
    redux
    react
    react-router
    react-router-redux

    View Slide

  12. The community

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  17. Common Pitfalls

    View Slide

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

    View Slide

  19. setState is asynchronous

    View Slide

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

    View Slide

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

    View Slide

  22. Multiple setState calls get batched

    View Slide

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

    View Slide

  24. Mutating the state is an anti-pattern

    View Slide

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

    View Slide

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

    View Slide

  27. State changes are shallow merged

    View Slide

  28. setState

    View Slide

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

    View Slide

  30. View Slide

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

    View Slide

  32. 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 Slide

  33. 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 Slide

  34. setState(updater, [callback])

    View Slide

  35. (prevState, props) => stateChange

    View Slide

  36. setState(stateChange, [callback])

    View Slide

  37. Best practices

    View Slide

  38. @dan_abramov, Jul 2016

    View Slide

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

    View Slide

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

    View Slide

  41. Testing

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  47. Separation of concerns

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  51. yarn add react-fetching

    View Slide

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

    View Slide

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

    View Slide

  54. yarn add react-refetch

    View Slide

  55. connect(mapPropsToRequests)(Component)

    View Slide

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

    View Slide

  57. Sharing state

    View Slide

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

    View Slide

  59. View Slide

  60. View Slide

  61. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  65. yarn add react-broadcast

    View Slide

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

    View Slide


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

    View Slide

  68. Time travel

    View Slide

  69. yarn add --dev react-lumberjack

    View Slide

  70. View Slide

  71. Lumberjack.back()
    Lumberjack.forward()

    View Slide

  72. Functional

    View Slide

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

    View Slide

  74. yarn add t-redux

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  79. State Management

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  83. Takeaways

    View Slide

  84. Keep it simple

    View Slide

  85. Lift your state up

    View Slide

  86. Have fun!

    View Slide

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

    View Slide