State Management Is Easy
Michel Weststrate�@mweststrate
Mendix�
React Amsterdam 2016
1
The DOM Was Hard...
2
State Management Is Hard
3
Redux: Simple & Elegant Concept
4
Pulls Amazing Tricks
5
New Things To Learn!
Reducers
Immutables
Denormalization
Connect
Selectors
Smart & Dumb components
Thunks & Sagas
6
MobX - No Pedaling
7
8
9
MobX
10
Why Is State Management Hard?
11
Σ
State
Aggregates
Lookup tables
Server Storage
UI
affects:
No Caching�No Data Duplication�No Cascading State Changes
Don't worry about how the app should react to state!
12
2. Everything Should Be Derived
Automatically
Define derivations & reactions
MobX ensures efficiency & consistency
13
14
Actions
State
Views
Modify
Updates
Σ
Simple
jsbin.com/hukiso/edit?js,output�github.com/mweststrate/mobx-contacts-list/
15
16
17
@observable / @computed
class Contact {
@observable title = "Mr"
@observable firstName = "Michel"
@observable lastName = "Moped"
@observable picture = {
thumbnail: null,
medium: null,
large: null
}
@observable tags = []
@computed get displayName() {
const cfl = capitalizeFirstLetter
return `${cfl(this.title)}. ${cfl(this.firstName)} ${cfl(this.lastName)}`
}
}
class Tag{
id;
@observable name = "Favorites"
}
18
observer
const ContactEntryView = observer(({contact, viewState}) =>
<ListItem
className={viewState.selection === contact ? 'selected' : null}
onClick={() => viewState.selectContact(contact) }
>
<Avatar src={contact.picture.thumbnail} />
{contact.displayName}
{contact.tags.map(tag => <input
type="button"
value={tag.name}
key={tag.id}
onClick={() => viewState.selectTag(tag)}
/>)}
</ListItem>
)
19
observer
20
@observer
@observer
export class ContactsOverview extends Component {
render() {
const {contactStore, viewState} = this.props;
return <List>
<RaisedButton
label="Add Contact"
onClick={() => contactStore.createRandomContact() }
/>
{ contactStore.pendingRequestCount > 0
? <RefreshIndicator />
: null
}
{ contactStore.contacts.map(contact =>
<ContactEntryView
contact={contact}
key={contact.id}
viewState={viewState}
/>
) }
</List>
}
}
21
Actions
createRandomContact() {
this.pendingRequestCount++
superagent.get('https://randomuser.me/api/').end((error, data) => {
const contact = new Contact(data)
this.contacts.push(contact)
this.pendingRequestCount--
}
}
22
@observable�enables MobX to observe your data
@observer�MobX ensures that this component is consistent with the state
@computed�MobX ensures that this value is consistent with the state
23
Fast
Numbers!
24
25
Such Fast
Only track data which is accessed in last render
Minimizes amount of computations
PureRenderMixin
26
Scalable
MobX @ Mendix
27
~500 classes
apidocs.mendix.com/modelsdk/
28
29
Demo
30
31
Scalable
32
Minimal state
Graphs: natural mental model
Simple code
Architectural freedom
Third party friendly
actions?
State
views?
Modify
Updates
State Management Is Simple!�Questions? #reactamsterdam @mweststrate
"I am putting my eggs into React and MobX basket. So far building two huge React apps I haven't had any reason to regret it."
"It's almost ridiculous how simple and powerful MobX + React is"
"Working with #mobx is basically a continuous loop of me going “this is way too simple, it definitely won’t work” only to be proven wrong"
"Try react-mobx with es6 and you will love it so much that you will hug someone."
"MobX compared to Redux feels like gravity gun compared to a wheelbarrow"
"I used to be Angular guy, but seeing how observables play well with React, �I would never go back to it."
"I have built big app with MobX already and comparing to the one before that which was using Redux, it is simpler to read and much easier to reason about."
"Cuts out much boilerplate and complexity."
"The #mobx is the way I always want things to be! It's really surprising simple and fast! Totally awesome! Don't miss it!"
33
Actions
State
Computed values
Modify
Updates
Reactions
Trigger
Events
Events invoke
Events invoke actions. Actions are the only thing that modify state and may have other side effects.
State is observable and minimally defined. Should not contain redundant or derivable data. Can be a graph, contain classes, arrays, refs, etc.
Computed values are values that can be derived from the state using a pure function. Will be updated automatically by MobX and optimized away if not in use.
Reactions are like computed values and react to state changes. But they produce a side effect instead of a value, like updating the UI.
@action onClick = () => {
this.props.todo.done = true;
}
@observable todos = [{
title: "learn MobX",
done: false
}]
@computed get completedTodos() {� return this.todos.filter(
todo => todo.done
)
}
const Todos = observer({ todos } =>
<ul>
todos.map(todo => <TodoView ... />
</ul>
)