1 of 34

State Management Is Easy

Michel Weststrate�@mweststrate

Mendix�

React Amsterdam 2016

1

2 of 34

The DOM Was Hard...

2

3 of 34

State Management Is Hard

3

4 of 34

Redux: Simple & Elegant Concept

4

5 of 34

Pulls Amazing Tricks

5

6 of 34

New Things To Learn!

Reducers

Immutables

Denormalization

Connect

Selectors

Smart & Dumb components

Thunks & Sagas

6

7 of 34

MobX - No Pedaling

7

8 of 34

8

9 of 34

9

10 of 34

MobX

  1. The Idea
  2. Simple
  3. Fast
  4. Scalable
  5. Questions

10

11 of 34

Why Is State Management Hard?

11

Σ

State

Aggregates

Lookup tables

Server Storage

UI

affects:

12 of 34

  1. State Should Be Minimally Defined

No Caching�No Data Duplication�No Cascading State Changes

Don't worry about how the app should react to state!

12

13 of 34

2. Everything Should Be Derived

Automatically

Define derivations & reactions

MobX ensures efficiency & consistency

13

14 of 34

14

Actions

State

Views

Modify

Updates

Σ

15 of 34

Simple

jsbin.com/hukiso/edit?js,output�github.com/mweststrate/mobx-contacts-list/

15

16 of 34

16

17 of 34

17

18 of 34

@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

19 of 34

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

20 of 34

observer

20

21 of 34

@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

22 of 34

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

23 of 34

@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

24 of 34

Fast

Numbers!

24

25 of 34

25

26 of 34

Such Fast

Only track data which is accessed in last render

Minimizes amount of computations

PureRenderMixin

26

27 of 34

Scalable

MobX @ Mendix

27

28 of 34

~500 classes

apidocs.mendix.com/modelsdk/

28

29 of 34

29

30 of 34

Demo

30

31 of 34

31

32 of 34

Scalable

32

Minimal state

Graphs: natural mental model

Simple code

Architectural freedom

Third party friendly

actions?

State

views?

Modify

Updates

33 of 34

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

34 of 34

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>

)