The state of the state: React state management in 2019

97d21da8e0ffa8f81218a293482c253a?s=47 Matheus
April 25, 2019

The state of the state: React state management in 2019

There's always been a large variety of ways to manage state in React. Redux has always been a popular choice, but with React 16, and recently released libraries, there are now even more options. What are these options, and why would you use any of these over any others?

Let's go through some popular choices for managing state in React and check their pros and cons and how opting in for each of these may help (or not) to scale your data flow.

97d21da8e0ffa8f81218a293482c253a?s=128

Matheus

April 25, 2019
Tweet

Transcript

  1. THE State of the state: React State Management IN 2019

    @YTHECOMBINATOR
  2. None
  3. 1PUB/42m

  4. None
  5. None
  6. None
  7. None
  8. None
  9. Bring me that!

  10. """

  11. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal REDUX-ACT IMMER
  12. https://github.com/GantMan/ReactStateMuseum

  13. "Javascript Fatigue" by Eric Cle!"ons

  14. HAS THE SO-CALLED JAVASCRIPT FATIGUE REACHED (REACT) STATE MANAGEMENT?

  15. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal IMMER REDUX-ACT
  16. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal IMMER REDUX-ACT
  17. Tldr; Offload store management logic to a separate web worker.

  18. https://github.com/developit/stockroom

  19. DEMO

  20. None
  21. None
  22. None
  23. HIGHLIGHTS: ↝ + Performance ↝ Good for CPU-bound store mutations

  24. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal IMMER REDUX-ACT
  25. Tldr; Declaratively describing the behaviour of your application

  26. FEATURING: ↝ A list of states ↝ One initial state

    ↝ A list of events that trigger transitions
  27. DEMO

  28. HIGHLIGHTS: ↝ Preciseness of specs ↝ Correctness of code ↝

    Less unimportant state / Less if clauses ↝ Leverage knowledge from non-coders too
  29. CONS: ↝ Surely an overkill for super simple components ↝

    Lack of familiarity from developers and designers ↝ Small ecosystem
  30. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal IMMER REDUX-ACT
  31. Tldr; Combine your local and remote state management

  32. Key Concepts: ↝ DEFAULTS: Your base state. What you start

    with. ↝ RESOLVERS: Where all the magic happens to retrieve and update your local data in the Apollo cache.
  33. DEMO

  34. HIGHLIGHTS: ↝ Getting Apollo set up just for state management

    can be a bit of work ↝ A natural way of querying and mutating state
  35. cons: ↝ Surely an overkill for apps that don't heavily

    depend on remote state
  36. None
  37. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal IMMER REDUX-ACT
  38. Tldr; Redux best practices without the boilerplate.

  39. https://github.com/jamiebuilds/unstated

  40. None
  41. https://github.com/pedronauck/reworm #

  42. import React from 'react' import { Provider, create } from

    'reworm' const { set, get } = create({ name: 'John' }) class App extends React.Component { componentDidMount() { set(prev $% ({ name: 'Peter' + prev.name })) } render() { return ( <Provider> <div>{get(s $% s.name)}</div> </Provider> ) } }
  43. HIGHLIGHTS: ↝ - Boilerplate ↝ + Simplicity

  44. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal IMMER REDUX-ACT
  45. Tldr; Recreate Redux in our React app without actually installing

    redux and react-redux
  46. Key Concepts: ↝ CONTEXT: Provides a way to pass data

    through the component tree without having to pass props down manually at every level. ↝ HOOKS: Let you use state and other React features without writing a class
  47. DEMO

  48. HIGHLIGHTS: ↝ Less boilerplate than redux itself ↝ No third-party

    dependencies
  49. cons: ↝ Still carries some of redux boilerplate ↝ You

    might face a few perf issues
  50. Split contexts that don't change together function Button() { let

    theme = useContext(ThemeContext); &' The rest of your rendering logic return <ExpensiveTree className={theme} />; }
  51. Split your component in two, put memo in between function

    Button() { let appContextValue = useContext(AppContext); let theme = appContextValue.theme; &' Your "selector" return <ThemedButton theme={theme} /> } const ThemedButton = memo(({ theme }) $% { &' The rest of your rendering logic return <ExpensiveTree className={theme} />; });
  52. One component with useMemo inside function Button() { let appContextValue

    = useContext(AppContext); let theme = appContextValue.theme; &' Your "selector" return useMemo(() $% { &' The rest of your rendering logic return <ExpensiveTree className={theme} />; }, [theme]) }
  53. HAS THE SO-CALLED JAVASCRIPT FATIGUE REACHED (REACT) STATE MANAGEMENT?

  54. HAS THE SO-CALLED JAVASCRIPT FATIGUE REACHED (REACT) STATE MANAGEMENT? Maybe!

    BUT SO HAS THE VANILLA WAY OF DOING THINGS!
  55. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal IMMER REDUX-ACT
  56. https://github.com/pauldijou/redux-act

  57. const serializeTodo = createAction('SERIALIZE_TODO'); serializeTodo(1); &' return { type: 'SERIALIZE_TODO',

    payload: 1 }
  58. const loading = createReducer({}, initialState.loading) .on(actions.fetch, () $% true) .on(actions.setQuery,

    () $% true) const ids = createReducer({}, initialState.ids) .on(actions.setIds, (state, payload) $% [&&.payload]) .on(actions.delete, (state, payload) $% { return [&&.state.filter((id) $% id ))* payload)]; });
  59. HIGHLIGHTS: ↝ Less boilerplate than plain redux ↝ Piping syntax

    for reducers
  60. Apollo link state Unstated Stockroom alfa MOBX setState() Redux CONTEXT

    HOOKS reworm Relay React Automata freactal IMMER REDUX-ACT
  61. ⚠ INTERMISSION ⚠ Immutability

  62. WHY: ↝ - Breakable ↝ + Debuggable ↝ + Performant

  63. WHY: ↝ - Breakable ↝ + Debuggable ↝ + Performant

  64. WHY: ↝ - Breakable ↝ + Debuggable ↝ + Performant

  65. WHY: ↝ - Breakable ↝ + Debuggable ↝ + Performant

  66. WHY: ↝ - Breakable ↝ + Debuggable ↝ + Performant

    Full Reconciliation REACT Reconciliation REACT + IMMUTABLE
  67. WHY: ↝ - Breakable ↝ + Debuggable ↝ + Performant

    Full Reconciliation O(N^3) REACT Reconciliation O(N) REACT + IMMUTABLE O(LOGN)
  68. https://github.com/immutable-js/immutable-js

  69. None
  70. ~300

  71. https://github.com/kolodny/immutability-helper

  72. import update from "i!"utability-helper" const reducer = (state, action) $%

    { switch (action.type) { case ADD_TAG: return update(state, { [action.id]: { tags: { $push: [action.tag] } } }) default: return state } }
  73. None
  74. https://github.com/immerjs/immer

  75. const map1 = { foo: 1, bar: 2 } const

    map2 = I!"utable.Map(map1) const { foo, bar } = map2 console.log(foo) &' undefined console.log(bar) &' undefined
  76. const map1 = { foo: 1, bar: 2 } const

    map2 = produce(map1, draft $% { draft.foo += 10 }) const { foo, bar } = map2 console.log(foo) &' 11 console.log(map1.bar ++, bar) &' true
  77. exposes a single default function that does all the work

    const map1 = { foo: 1, bar: 2 } const map2 = produce(map1, draft $% { draft.foo += 10 }) const { foo, bar } = map2 console.log(foo) &' 11 console.log(map1.bar ++, bar) &' true
  78. const map1 = { foo: 1, bar: 2 } const

    map2 = produce(map1, draft $% { draft.foo += 10 }) const { foo, bar } = map2 console.log(foo) &' 11 console.log(map1.bar ++, bar) &' true apply all your changes to a temporarily draft State, which is a proxy of the currentState.
  79. your objects and arrays are really JavaScript objects and arrays,

    so you can do everything you would normally do const map1 = { foo: 1, bar: 2 } const map2 = produce(map1, draft $% { draft.foo += 10 }) const { foo, bar } = map2 console.log(foo) &' 11 console.log(map1.bar ++, bar) &' true
  80. &' add a tag to a todo { &&.state, [action.id]:

    { &&.state[action.id], tags: [ &&.state[action.id].tags, action.tag ] } } &' add a tag to a todo state[action.id].tags.push(action.tag)
  81. ALSO: ↝ ES5 Fallback ↝ Strongly typed ↝ Small (4KB)

    ↝ Currying
  82. ALSO: ↝ Fast Auto freezing ↝ Equivalent perf to ImmutableJS

    ↝ Supports hooks!
  83. None
  84. None
  85. ⚠ ❌ ❌ ⚠

  86. ~ senior software engineer, Front-End @beakyn ~ @ythecombinator on the

    webs ~ addicted to emojis, memes and beer
  87. https://bit.ly/react-state-management-in-2019

  88. THANKS! @YTHECOMBINATOR