"Nobody knows how to do anything without Redux anymore. It's ridiculous." - @mjackson Let's fix it!
setState ftw@MicheleBertoli
View Slide
My name’s Michele and I’m a Reactfanboy since 2014
I work in Ads at Facebook, and Icontribute to a pretty sophisticatedReact UI
setState is the primary method you useto update the UI in React
Are we really going to talk aboutsetState for 40 minutes?
YES
Ok, why?
“I’m learning React but I don’tunderstand reducers.”Anonymous, Mar 2017
react
react-reduxreduxreactreact-routerreact-router-redux
The community
“Nobody knows how to doanything without Reduxanymore. It's ridiculous.”@mjackson, Jun 2016
“3 Reasons why I stoppedusing React.setState.”@mweststrate, Jun 2016
“I love setState. In 3 1/2 years,I haven't needed anythingmore.”@chantastic, Mar 2017
“You might not need Redux.”@dan_abramov, Sep 2016
Common Pitfalls
setState({ title: 'Here comes the sun' })console.log(this.state.title)
setState is asynchronous
setState({ counter: this.state.counter + 1 })setState({ counter: this.state.counter + 1 })
Object.assign(prevState,{ counter: this.state.counter + 1 },{ counter: this.state.counter + 1 },)
Multiple setState calls get batched
this.state.title = 'Come together'
Mutating the state is an anti-pattern
this.state = {song: {title: 'Let it be',year: 1970,},}
this.setState({song: {title: 'Hey Jude',},})
State changes are shallow merged
setState
yarn add setstate- DON’T TRY THIS AT HOME -
“If setState was packaged upas a lib, people would love it.”@chantastic, Jul 2017
setState enqueues changes to the component stateand tells React that a component and its childrenneed to be re-rendered with the updated state.
setState(updater, [callback])
(prevState, props) => stateChange
setState(stateChange, [callback])
Best practices
@dan_abramov, Jul 2016
this.state = {price: `${props.currency}${props.value}`,}Don’t
this.setState({request: API.get(...),})Don’t
Testing
this.setState((prevState, props) => ({counter: prevState.counter + props.step,}))
export const increment =(prevState, props) => ({counter: prevState.counter + props.step,})
import { increment } from './updaters'this.setState(increment)
test('increment', () => {const prevState = { counter: 1 }const props = { step: 1 }expect(increment(prevState, props)).toEqual({ counter: 2 })})
test('increment', () => {const prevState = { counter: 1 }const props = { step: 1 }expect(increment(prevState, props)).toMatchSnapshot()})
Separation of concerns
● Container: data and behaviour● Presentational: appearanceContainer and Presentational
componentDidMount() {API.get(...).then(s => this.setState(s))}render() {return }
cb() {API.post(...).then(s => this.setState(s))}render() {return }
yarn add react-fetching
url="https://api.punkapi.com/v2/beers"ok={beers => {beers[0].name}}/>
● Higher-order components● Component => Component● Options => Component => ComponentComposition
yarn add react-refetch
connect(mapPropsToRequests)(Component)
connect(() => ({f: 'https://api.punkapi.com/v2/beers'}))(({ f }) => f.fulfilled? {f.value[0].name}: null)
Sharing state
Do you even lift (your state up)?
componentDidMount() {API.get(...).then(s => this.setState(s))}render() {return {this.state.data}}
componentDidMount() {API.get(...).then(this.props.cb)}render() {return {this.props.data}}
cb(data) {this.setState({ data })}render() {return }
yarn add react-broadcast
channel="state"value={this.state}>{this.props.children}
{state => ({state.data})}
Time travel
yarn add --dev react-lumberjack
Lumberjack.back()Lumberjack.forward()
Functional
dispatch(action) {this.setState(prevState => reducer(prevState, action))}
yarn add t-redux
const reducer = buildReducer({'INCREMENT': state => ({counter: state.counter + 1,}),})const initialState = { counter: 0 }
const inc = () => dispatcher.dispatch({type: 'INCREMENT',})const Button = ({ counter }) => ({counter})
withState([reducer], initialState)(Button)
● Best practices● Testing● Separation of concerns● Sharing state● Time Travel● FunctionalRecap
State Management
● Higher-order components● Immutability● Pure functions● Generators● ObservablesRequirements
● Make informed decisions about your tools● Understand the tradeoffs involved in eachdecisionChoose wisely
● react-redux uses setState● mobx-react uses forceUpdateKnow your tools
Takeaways
Keep it simple
Lift your state up
Have fun!
Michele BertoliFront End Engineer at FacebookAuthor of React Design Patterns and Best PracticesFollow me @MicheleBertoli