Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / devtools / docs / contributor / frontend / redux.md
blobe090060f5d76995f05cc7641fab97bd850559408
2 We use [Redux](https://github.com/reactjs/redux) to manage application
3 state. The [docs](http://redux.js.org/) do a good job explaining the
4 concepts, so go read them.
6 # Quick Intro
8 Just like the [React introduction](react.md), this is a quick
9 introduction to redux, focusing on how it fits into React and why we
10 chose it.
12 One of the core problems that React does not address is managing
13 state. In the React intro, we talked about data flowing down and
14 events flowing up. Conceptually this is nice, but you quickly run into
15 awkward situations in large apps.
17 Let's look at an example. Say you have a page with a tabbed interface.
18 Here, `Tab1` is managing a list of items, so naturally it uses local
19 state. `Tab2` renders different stuff.
21 ```js
22 const Tab1 = React.createClass({
23   getInitialState: function() {
24     return { items: [] };
25   },
27   handleAddItem: function(item) {
28     this.setState({ items: [...this.state.items, item]});
29   },
31   render: function() {
32     /* ... Renders the items and button to add new item ... */
33   }
34 });
36 const Tab2 = React.createClass({
37   render: function() {
38     /* ... Renders other data ... */
39   }
40 });
42 // Assume `Tab1` and `Tab2` are wrapped with a factory when importing
43 const Tabs = React.createClass({
44   render: function() {
45     return div(
46       { className: 'tabs' },
47       // ... Render the tab buttons ...
48       Tab1(),
49       Tab2()
50     );
51   }
52 });
53 ```
55 What happens when `Tab2` needs the list of items though? This scenario
56 comes up all time: components that aren't directly related need access
57 to the same state. A small change would be to move the `items` state
58 up to the `Tabs` component, and pass it down to both `Tab1` and `Tab2`.
60 But now `Tabs` has to implement the `handleAddItem` method to add an
61 item because it's managing that state. This quickly gets ugly as the
62 end result is the root component ends up with a ton of state and
63 methods to manage it: a [god
64 component](https://en.wikipedia.org/wiki/God_object) is born.
66 Additionally, how do we know what data each tab needs? We end up
67 passing *all* the state down because we don't know. This is not a
68 modular solution: one object managing the state and every component
69 receiving the entire state is like using tons of global variables.
71 ## Evolution of Flux
73 Facebook addressed this with the
74 [flux](https://facebook.github.io/flux/) architecture, which takes the
75 state out of the components and into a "store". Redux is the latest
76 evolution of this idea and solves a lot of problems previous flux
77 libraries had (read it's documentation for more info).
79 Because the state exists outside the component tree, any component can
80 read from it. Additionally, **state is updated with
81 [actions](http://redux.js.org/docs/basics/Actions.html)** that any
82 component can fire. We have [guidelines](redux-guidelines) for where
83 to read/write state, but it completely solves the problem described
84 above. Both `Tab1` and `Tab2` would be listening for changes in the
85 `item` state, and `Tab1` would fire actions to change it.
87 With redux, **state is managed modularly with
88 [reducers](http://redux.js.org/docs/basics/Reducers.html)** but tied
89 together into a single object. This means a single JS object
90 represents most* of your state. It may sound crazy at first, but think
91 of it as an object with references to many pieces of state; that's all
92 it is.
94 This makes it very easy to test, debug, and generally think about. You
95 can log your entire state to the console and inspect it. You can even
96 dump in old states and "replay" to see how the UI changed over time.
98 I said "most*" because it's perfectly fine to use both component local
99 state and redux. Be aware that any debugging tools will not see local
100 state at all though. It should only be used for transient state; we'll
101 talk more about that in the guidelines.
103 ## Immutability
105 Another important concept is immutability. In large apps, mutating
106 state makes it very hard to track what changed when. It's very easy to
107 run into situations where something changes out from under you, and
108 the UI is rendered with invalid data.
110 Redux enforces the state to be updated immutably. That means you
111 always return new state. It doesn't mean you do a deep copy of the
112 state each time: when you need to change some part of the tree you
113 only need to create new objects to replace the ones your changing (and
114 walk up to the root to create a new root). Unchanged subtrees will
115 reference the same objects.
117 This removes a whole class of errors, almost like Rust removing a
118 whole class of memory errors by enforcing ownership.
120 ## Order of Execution
122 One of best things about React is that **rendering is synchronous**. That
123 means when you render a component, given some data, it will fully
124 render in the same tick. If you want the UI to change over time, you
125 have to change the *data* and rerender, instead of arbitrary UI
126 mutations.
128 The reason this is desired is because if you build the UI around
129 promises or event emitters, updating the UI becomes very brittle
130 because anything can happen at any time. The state might be updated in
131 the middle of rendering it, maybe because you resolved a few promises
132 which made your rendering code run a few ticks later.
134 Redux embraces the synchronous execution semantics as well. What this
135 means is that everything happens in a very controlled way. When
136 updating state through an action, all reducers are run and a new state
137 is synchronously generated. At that point, the new state is handed off
138 to React and synchronously rendered.
140 Updating and rendering happen in two phases, so the UI will *always*
141 represent consistent state. The state can never be in the middle of
142 updating when rendering.
144 What about asynchronous work? That's where
145 [middleware](http://redux.js.org/docs/advanced/Middleware.html) come
146 in. At this point you should probably go study our code, but
147 middleware allows you to dispatch special actions that indicate
148 asynchronous work. The middleware will catch these actions and do
149 something async, dispatching "raw" actions along the way (it's common
150 to emit a START, DONE, and ERROR action).
152 **Ultimately there are 3 "phases" or level of abstraction**: the async
153 layer talks to the network and may dispatch actions, actions are
154 synchronously pumped through reducers to generate state, and state is
155 rendered with react.
157 ## Next
159 Read the [Redux Guidelines](redux-guidelines.md) next to learn how to
160 write React code specifically for the devtools.