SlideShare una empresa de Scribd logo
1 de 150
Descargar para leer sin conexión
1
ReduxRedux
Raise your hand if you used in production...Raise your hand if you used in production...
2
MobXMobX
Raise your hand if you used in production...Raise your hand if you used in production...
3
React.createContextReact.createContext
Do you want to experiment with justDo you want to experiment with just
I hope I'll change your idea!
I hope I'll change your idea!
4
Ego SlideEgo Slide
@mattiamanzati
5
What does anWhat does an
application needs?application needs?
6
What does anWhat does an
application needs?application needs?
STORE ITS STATE
6
What does anWhat does an
application needs?application needs?
STORE ITS STATEMODIFY ITS STATE
6
What does anWhat does an
application needs?application needs?
STORE ITS STATEMODIFY ITS STATE
VIEW ITS STATE
AGGREGATED
6
What does anWhat does an
application needs?application needs?
STORE ITS STATEMODIFY ITS STATE
VIEW ITS STATE
AGGREGATED
PERFORM
SIDE EFFECTS
6
...JavaScript?...JavaScript?
7
...JavaScript?...JavaScript?
{ 
name: "work", 
done: false 
}
7
...JavaScript?...JavaScript?
{ 
name: "work", 
done: false 
}
onClick = () =>{ 
todo.done = true 
}
7
...JavaScript?...JavaScript?
{ 
name: "work", 
done: false 
}
onClick = () =>{ 
todo.done = true 
}
get totalCount(){ 
return this.todos.length 
}
7
...JavaScript?...JavaScript?
{ 
name: "work", 
done: false 
}
onClick = () =>{ 
todo.done = true 
}
get totalCount(){ 
return this.todos.length 
}
???
7
MobXMobX
8
MobXMobX
Reactive library
8
MobXMobX
Reactive library
No concept of stream
8
MobXMobX
Reactive library
No concept of stream
Uses Proxies (ES6+) or Atoms (ES5-)
8
ObservablesObservables
ActionsActions
9
ObservablesObservables
Store your application state
ActionsActions
9
ObservablesObservables
Store your application state
State may change over time
ActionsActions
9
ObservablesObservables
Store your application state
State may change over time
Observable instance may be the same
ActionsActions
9
ObservablesObservables
Store your application state
State may change over time
Observable instance may be the same
ActionsActions
Change observables state value
9
ObservablesObservables
Store your application state
State may change over time
Observable instance may be the same
ActionsActions
Change observables state value
Can be triggered from UI or side effects
9
ComputedsComputeds
ReactionsReactions
10
ComputedsComputeds
Derived state data
ReactionsReactions
10
ComputedsComputeds
Derived state data
Automatically updated synchronusly
ReactionsReactions
10
ComputedsComputeds
Derived state data
Automatically updated synchronusly
Always up to date with current
observable state
ReactionsReactions
10
ComputedsComputeds
Derived state data
Automatically updated synchronusly
Always up to date with current
observable state
ReactionsReactions
Trigger functions when a condition changes
10
ComputedsComputeds
Derived state data
Automatically updated synchronusly
Always up to date with current
observable state
ReactionsReactions
Trigger functions when a condition changes
UI is a reaction of the store state
10
A successful pattern inA successful pattern in
history!history!
11
12
Excel is Reactive!Excel is Reactive!
13
Excel is Reactive!Excel is Reactive!
CELLS
13
Excel is Reactive!Excel is Reactive!
CELLSUSER INTERACTION
13
Excel is Reactive!Excel is Reactive!
CELLSUSER INTERACTION
FORMULAS
13
Excel is Reactive!Excel is Reactive!
CELLSUSER INTERACTION
FORMULAS
SCREEN UPDATES
13
Let's start!Let's start!
A classic example: TODO ListsA classic example: TODO Lists
14
class App extends React.Component {
// observable values
currentText = "";
todos = [];
// actions
addTodo = () => {
this.todos.push({ name: this.currentText, done: false });
this.currentText = "";
};
toggleTodo = todo => {
todo.done = !todo.done;
};
setCurrentText = text => {
this.currentText = text;
};
// computed
get pendingCount() {
return this.todos.filter(todo => !todo.done).length;
}
// ...
} 15
class App extends React.Component {
// observable values
currentText = "";
todos = [];
// actions
addTodo = () => {
this.todos.push({ name: this.currentText, done: false });
this.currentText = "";
};
toggleTodo = todo => {
todo.done = !todo.done;
};
setCurrentText = text => {
this.currentText = text;
};
// computed
get pendingCount() {
return this.todos.filter(todo => !todo.done).length;
}
// ...
} 15
class App extends React.Component {
// observable values
currentText = "";
todos = [];
// actions
addTodo = () => {
this.todos.push({ name: this.currentText, done: false });
this.currentText = "";
};
toggleTodo = todo => {
todo.done = !todo.done;
};
setCurrentText = text => {
this.currentText = text;
};
// computed
get pendingCount() {
return this.todos.filter(todo => !todo.done).length;
}
// ...
} 15
class App extends React.Component {
// observable values
currentText = "";
todos = [];
// actions
addTodo = () => {
this.todos.push({ name: this.currentText, done: false });
this.currentText = "";
};
toggleTodo = todo => {
todo.done = !todo.done;
};
setCurrentText = text => {
this.currentText = text;
};
// computed
get pendingCount() {
return this.todos.filter(todo => !todo.done).length;
}
// ...
} 15
class App extends React.Component {
// ...
// render observer
render() {
return (
<div className="App">
<h1>TODOs</h1>
<input
type="text"
value={this.currentText}
onChange={e => this.setCurrentText(e.target.value)}
/>
<button onClick={this.addTodo}>Add</button>
<ul>
{this.todos.map(item => (
<li onClick={() => this.toggleTodo(item)}>
{item.name} {item.done ? <i>DONE!</i> : null}
</li>
))}
</ul>
<p>There are {this.pendingCount} pending todos.</p>
</div>
);
16
class App extends React.Component {
// ...
// render observer
render() {
return (
<div className="App">
<h1>TODOs</h1>
<input
type="text"
value={this.currentText}
onChange={e => this.setCurrentText(e.target.value)}
/>
<button onClick={this.addTodo}>Add</button>
<ul>
{this.todos.map(item => (
<li onClick={() => this.toggleTodo(item)}>
{item.name} {item.done ? <i>DONE!</i> : null}
</li>
))}
</ul>
<p>There are {this.pendingCount} pending todos.</p>
</div>
);
16
class App extends React.Component {
// ...
}
const MyApp = observer(App);
decorate(App, {
currentText: observable,
todos: observable,
addTodo: action,
toggleTodo: action,
setCurrentText: action,
pendingCount: computed
});
const rootElement = document.getElementById("root");
ReactDOM.render(<MyApp />, rootElement);
17
class App extends React.Component {
// ...
}
const MyApp = observer(App);
decorate(App, {
currentText: observable,
todos: observable,
addTodo: action,
toggleTodo: action,
setCurrentText: action,
pendingCount: computed
});
const rootElement = document.getElementById("root");
ReactDOM.render(<MyApp />, rootElement);
17
Few notes:Few notes:
Component state managed byComponent state managed by
MobX or not?MobX or not?
class App extends React.Component {
@observable
currentText = ""
// ...
}
export default observer(App)
class App extends React.Component {
state = {
currentText: ""
}
// ...
} 18
Few notes:Few notes:
Component state managed byComponent state managed by
MobX or not?MobX or not?
class App extends React.Component {
@observable
currentText = ""
// ...
}
export default observer(App)
19
Few notes:Few notes:
Component state managed byComponent state managed by
MobX or not?MobX or not?
Better optimized than setState
class App extends React.Component {
@observable
currentText = ""
// ...
}
export default observer(App)
19
Few notes:Few notes:
Component state managed byComponent state managed by
MobX or not?MobX or not?
Better optimized than setState
Simpler API than setState
class App extends React.Component {
@observable
currentText = ""
// ...
}
export default observer(App)
19
Few notes:Few notes:
Component state managed byComponent state managed by
MobX or not?MobX or not?
Better optimized than setState
Simpler API than setState
Easier to refactor to a separate store
class App extends React.Component {
@observable
currentText = ""
// ...
}
export default observer(App)
19
Few notes:Few notes:
Decorators are optionalDecorators are optional
class Store {
@observable
todos = []
}
class Store {
todos = []
}
decorate(Store, {
todos: observable
});
20
Few notes:Few notes:
Classes are optionalClasses are optional
class Store {
@observable
todos = []
}
const store = new Store()
const store = observable({
todos: []
})
21
MobX is unopinionatedMobX is unopinionated
22
MobX is unopinionatedMobX is unopinionated
How do I X?
22
MobX is unopinionatedMobX is unopinionated
How do I X?
Should I MVC?
22
MobX is unopinionatedMobX is unopinionated
How do I X?
Should I MVC?
Should I MVVM?
22
MobX is unopinionatedMobX is unopinionated
How do I X?
Should I MVC?
Should I MVVM?
Should I MVP?
22
MobX is unopinionatedMobX is unopinionated
How do I X?
Should I MVC?
Should I MVVM?
Should I MVP?
Should I Flux?
22
MobX is aMobX is a
reactive data libraryreactive data library
23
It works!It works!
24
It works!It works!
Does it scales?
Does it scales?
24
It works!It works!
Is it testable?
Is it testable?
Does it scales?
Does it scales?
24
It works!It works!
Is it testable?
Is it testable?
Mix BL and UI?
Mix BL and UI?
Does it scales?
Does it scales?
24
Don't mix Business Logic & UIDon't mix Business Logic & UI
25
Don't mix Business Logic & UIDon't mix Business Logic & UI
What if we want a React Native app later?
25
Don't mix Business Logic & UIDon't mix Business Logic & UI
What if we want a React Native app later?
What if UI framework changes?
25
Don't mix Business Logic & UIDon't mix Business Logic & UI
What if we want a React Native app later?
What if UI framework changes?
What if we need SSR?
25
Don't mix Business Logic & UIDon't mix Business Logic & UI
What if we want a React Native app later?
What if UI framework changes?
What if we need SSR?
25
Don't mix Business Logic & UIDon't mix Business Logic & UI
class Store {
// observable values
currentText = "";
todos = [];
// actions
addTodo = () => {
this.todos.push({ name: this.currentText, done: false });
this.currentText = "";
};
toggleTodo = todo => { todo.done = !todo.done; };
setCurrentText = text => { this.currentText = text; };
// computed
get pendingCount() {
return this.todos.filter(todo => !todo.done).length;
}
}
Extracting the StoreExtracting the Store
26
class Store {
// ...
}
class App extends React.Component {
// ...
}
const MyApp = observer(Store);
const store = new Store();
const rootElement = document.getElementById("root");
ReactDOM.render(<MyApp store={store} />, rootElement);
Don't mix Business Logic & UIDon't mix Business Logic & UI
Wiring the Store as propWiring the Store as prop
27
import { observer, Provider, inject }
from "mobx-react";
// ...
const MyApp = inject("store")(observer(App));
const store = new Store();
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<MyApp />
</Provider>, rootElement);
Don't mix Business Logic & UIDon't mix Business Logic & UI
Use Provider & InjectUse Provider & Inject
28
import { observer, Provider, inject }
from "mobx-react";
// ...
const MyApp = inject("store")(observer(App));
const store = new Store();
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<MyApp />
</Provider>, rootElement);
Don't mix Business Logic & UIDon't mix Business Logic & UI
Use Provider & InjectUse Provider & Inject
No need to pass down manually your stores
28
import { observer, Provider, inject }
from "mobx-react";
// ...
const MyApp = inject("store")(observer(App));
const store = new Store();
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<MyApp />
</Provider>, rootElement);
Don't mix Business Logic & UIDon't mix Business Logic & UI
Use Provider & InjectUse Provider & Inject
No need to pass down manually your stores
Allows to change store implementation in your tests
28
import { observer, Provider, inject }
from "mobx-react";
// ...
const MyApp = inject("store")(observer(App));
const store = new Store();
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<MyApp />
</Provider>, rootElement);
Don't mix Business Logic & UIDon't mix Business Logic & UI
Use Provider & InjectUse Provider & Inject
No need to pass down manually your stores
Allows to change store implementation in your tests
Only one point of store injections into the views
28
Real-World ArchitectureReal-World Architecture
Current State RecapCurrent State Recap
VIEW
STORE
Renders the view and
calls actions on the store
Holds and modify domain state
Holds and modify application state
Implements business logic
Fetch from API
Implements view actions
Aggregates data for the view
29
Real-World ArchitectureReal-World Architecture
Current State RecapCurrent State Recap
VIEW
STORE
Renders the view and
calls actions on the store
Holds and modify domain state
Holds and modify application state
Implements business logic
Fetch from API
Implements view actions
Aggregates data for the view
W
ay too m
uch
W
ay too m
uch
things!
things!
29
Domain StateDomain State
WTF is dat?WTF is dat?
30
Domain StateDomain State
WTF is dat?WTF is dat?
Is the domain of your app
in our example, of Todo
30
Domain StateDomain State
WTF is dat?WTF is dat?
Is the domain of your app
in our example, of Todo
Describes the application entities and relations
30
Domain StateDomain State
WTF is dat?WTF is dat?
Is the domain of your app
in our example, of Todo
Describes the application entities and relations
Usually it is persistent and stored somewhere
30
Domain StateDomain State
WTF is dat?WTF is dat?
Is the domain of your app
in our example, of Todo
Describes the application entities and relations
Usually it is persistent and stored somewhere
Not tight with the UI
30
Domain StateDomain State
WTF is dat?WTF is dat?
Is the domain of your app
in our example, of Todo
Describes the application entities and relations
Usually it is persistent and stored somewhere
Not tight with the UI
Highly reusable
30
Domain StateDomain State
first implementationfirst implementation
class Todo {
name = "";
done = false;
}
decorate(Todo, {
name: observable,
done: observable
});
class Store {
// ...
addTodo = () => {
const todo = new Todo();
todo.name = this.currentText;
this.todos.push(todo);
this.currentText = "";
};
}
31
Domain StateDomain State
domain actionsdomain actions
// domain todo model
class Todo {
name = "";
done = false;
toggle(){
this.done = !this.done
}
}
decorate(Todo, {
// ...
toggle: action
});
Observables should be changed trough actions! So it's a
good idea to define dumb actions on our domain model!
32
Domain StateDomain State
let's be more real!let's be more real!
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0; // UHM... is this ok?
// ...
}
// domain user model
class User {
id = 0
name = ""
}
33
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
34
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
Normalized
34
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
Normalized
Object tree
34
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
Normalized
Object tree
Easily serialize
34
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
Normalized
Object tree
Easily serialize
Difficult access 34
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
Normalized
Object tree
Easily serialize
Difficult access
Denormalized
34
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
Normalized
Object tree
Easily serialize
Difficult access
Denormalized
Object graph
34
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
Normalized
Object tree
Easily serialize
Difficult access
Denormalized
Object graph
Harder serialization
34
Domain StateDomain State
tree or graph?tree or graph?
// domain todo model
class Todo {
name = "";
done = false;
user_id = 0;
// ...
}
// domain user model
class User {
id = 0
name = ""
}
// domain todo model
class Todo {
name = "";
done = false;
user = new User(0, "");
// ...
}
// domain user model
class User {
id = 0
name = ""
}
Normalized
Object tree
Easily serialize
Difficult access
Denormalized
Object graph
Harder serialization
Easy access 34
Domain StateDomain State
good news everyone!good news everyone!
35
Domain StateDomain State
lets do both!lets do both!
// domain todo model
class Todo {
name = ""
done = false
user_id = 0
get user(){
return store.getUserById(this.user_id) // <- WTF
}
set user(value){
this.user_id = value.id
}
}
decorate(Todo, {
//...
user_id: observable,
user: computed
}) 36
Domain StateDomain State
lets do both!lets do both!
// domain todo model
class Todo {
name = ""
done = false
user_id = 0
get user(){
return store.getUserById(this.user_id) // <- WTF
}
set user(value){
this.user_id = value.id
}
}
decorate(Todo, {
//...
user_id: observable,
user: computed
}) 36
Multiple Store CommunicationMultiple Store Communication
available pattersavailable patters
37
Multiple Store CommunicationMultiple Store Communication
available pattersavailable patters
Singleton instance & require/import
37
Multiple Store CommunicationMultiple Store Communication
available pattersavailable patters
Singleton instance & require/import
Dependency injection framework
37
Multiple Store CommunicationMultiple Store Communication
available pattersavailable patters
Singleton instance & require/import
Dependency injection framework
Root store pattern
37
Multiple Store CommunicationMultiple Store Communication
root store patternroot store pattern
class RootStore {
todoStore = null;
fetch = null;
apiKey = "";
constructor(fetch, apiKey){
this.fetch = fetch
this.apiKey = apiKey
this.todoStore = new Store(this)
}
}
class Todo {
store = null;
constructor(store){ this.store = store }
}
class Store {
rootStore = null;
constructor(rootStore){ this.rootStore = rootStore }
} 38
Multiple Store CommunicationMultiple Store Communication
root store patternroot store pattern
39
Multiple Store CommunicationMultiple Store Communication
root store patternroot store pattern
Central point for each store to
communicate
39
Multiple Store CommunicationMultiple Store Communication
root store patternroot store pattern
Central point for each store to
communicate
Strongly typed
39
Multiple Store CommunicationMultiple Store Communication
root store patternroot store pattern
Central point for each store to
communicate
Strongly typed
Works as dependency root
Can host environment specific variables
39
Multiple Store CommunicationMultiple Store Communication
root store patternroot store pattern
Central point for each store to
communicate
Strongly typed
Works as dependency root
Can host environment specific variables
Very easily testable
39
Multiple Store CommunicationMultiple Store Communication
back to our problemback to our problem
// domain todo model
class Todo {
name = ""
done = false
user_id = 0
store = null;
constructor(store){ this.store = store; }
get user(){
return this.store.rootStore
.userStore.getUserById(this.user_id)
}
set user(value){
this.user_id = value.id
}
}
40
Multiple Store CommunicationMultiple Store Communication
back to our problemback to our problem
import { observer, Provider,
inject } from "mobx-react";
// ...
const MyApp = inject("store")(observer(App));
const store = new RootStore(window.fetch);
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<MyApp />
</Provider>, rootElement);
41
Multiple Store CommunicationMultiple Store Communication
back to our problemback to our problem
test("it should restore data from API", async t => {
const fakeFetch = () => Promise.resolve({
data: [{id: 1, name: "Mattia"}]
})
const store = new RootStore(fakeFetch)
await store.userStore.fetchAll()
t.equal(store.userStore.users[0].name, "Mattia")
})
42
Real-World ArchitectureReal-World Architecture
Current State RecapCurrent State Recap
VIEW
STORE
Renders the view and
calls actions on the store
Holds domain state
Create and modify domain state
Holds and modify application state
Implements business logic
Fetch from API
Aggregates data for the view
DOMAIN MODEL
43
Real-World ArchitectureReal-World Architecture
Current State RecapCurrent State Recap
VIEW
STORE
Renders the view and
calls actions on the store
Holds domain state
Create and modify domain state
Holds and modify application state
Implements business logic
Fetch from API
Aggregates data for the view
DOMAIN MODEL
43
Domain Model SerializationDomain Model Serialization
turning JSON into observablesturning JSON into observables
44
Domain Model SerializationDomain Model Serialization
turning JSON into observablesturning JSON into observables
Our state is an object tree
44
Domain Model SerializationDomain Model Serialization
turning JSON into observablesturning JSON into observables
Our state is an object tree
Unfortunately it's not a plain JS object
44
Domain Model SerializationDomain Model Serialization
turning JSON into observablesturning JSON into observables
Our state is an object tree
Unfortunately it's not a plain JS object
Most APIs provide JSON as intermediate language
44
Domain Model SerializationDomain Model Serialization
turning JSON into observablesturning JSON into observables
Our state is an object tree
Unfortunately it's not a plain JS object
Most APIs provide JSON as intermediate language
We need to provide conversions to serialize or
deserialize our state
44
Domain Model SerializationDomain Model Serialization
deserializationdeserialization
class Todo {
// ...
constructor(store, data){
this.store = store
if(data) Object.assign(this, data)
}
}
45
Domain Model SerializationDomain Model Serialization
serializationserialization
class Todo {
// ...
get toJSON(){
return {
name: this.name,
done: this.done
}
}
}
// ...
decorate(Todo, {
toJSON: computed
})
JSON is just another view of the domain model,
so we can just derive itderive
46
Domain Model SerializationDomain Model Serialization
packagespackages
class User {
@serializable(identifier()) id = 0;
@serializable name = '';
}
class Todo {
@serializable name = '';
@serializable done = false;
@serializable(object(User)) user = null;
}
// You can now deserialize and serialize!
const todo = deserialize(Todo, {
name: 'Hello world',
done: true,
user: { id: 1, name: 'Mattia' }
});
const todoJSON = serialize(todo)
with serializr you get that with tagging your domain models
47
Domain Model SerializationDomain Model Serialization
the deserialization problemthe deserialization problem
class TodoStore {
todos = []
fromCache(){
const cachedData = localStorage.getItem("todos")
|| "[]"
this.todos = JSON.parse(cachedData)
.map(data => new Todo(this, data)
}
getById = id => this.todos
.find(item => item.id === id)
}
decorate(TodoStore, {
fromCache: action
})
deserializing is memory intensive!
48
MobX hidden featureMobX hidden feature
_interceptReads_interceptReads
import {_interceptReads} from "mobx"
const todos = observable.map()
_interceptReads(todos, value => value + "! LOL")
todos.set(1, "Mattia")
console.log(todos.get("1")) // => Mattia! LOL
undocumented (yet there since 2017) mobx feature
allows to transform mobx values while reading
available for objects, arrays, maps and boxed values
49
MobX hidden featureMobX hidden feature
_interceptReads to the rescue!_interceptReads to the rescue!
class TodoStore {
todos = []
_cache = {}
constructor(rootStore){
this.rootStore = rootStore
// ...
_interceptReads(this.todos, this.unboxTodo)
}
unboxTodo = data => {
if(this._cache[data.id]){
return this._cache[data.id]
}
this._cache[data.id] = new Todo(this, data)
return this._cache[data.id]
}
}
50
MobX PerformanceMobX Performance
better performant domain storesbetter performant domain stores
51
MobX PerformanceMobX Performance
better performant domain storesbetter performant domain stores
Use ES6 Maps and lookup by ID when possible
51
MobX PerformanceMobX Performance
better performant domain storesbetter performant domain stores
Use ES6 Maps and lookup by ID when possible
Store JSON in an observable map
51
MobX PerformanceMobX Performance
better performant domain storesbetter performant domain stores
Use ES6 Maps and lookup by ID when possible
Store JSON in an observable map
Use _interceptReads to perform lazy deserialization
51
MobX PerformanceMobX Performance
better performant domain storesbetter performant domain stores
Use ES6 Maps and lookup by ID when possible
Store JSON in an observable map
Use _interceptReads to perform lazy deserialization
Implement ID -> name without deserialization
51
Real-World ArchitectureReal-World Architecture
Current State RecapCurrent State Recap
VIEW
REPOSITORY
Renders the view and
calls actions on the store
Holds domain state
Create and modify domain state
Fetch from API
Holds and modify application state
Implements business logic
Aggregates data for the view
STORE
DOMAIN MODEL
52
Real-World ArchitectureReal-World Architecture
Current State RecapCurrent State Recap
VIEW
REPOSITORY
Renders the view and
calls actions on the store
Holds domain state
Create and modify domain state
Fetch from API
Holds and modify application state
Implements business logic
Aggregates data for the view
STORE
DOMAIN MODEL
52
class Overview {
rootStore = null
currentText = ""
constructor(rootStore){ this.rootStore = rootStore }
get todos(){
// perform sorting and pagining here
return this.rootStore.todoStore.todos
}
handleAddClicked(){
this.rootStore.todoStore.addTodo(this.currentText)
this.currentText = ""
}
}
decorate(Router, {
todos: computed,
currentText: observable,
handleAddClicked: action
})
53
Services & PresentersServices & Presenters
routingrouting
class Router {
uri = "/"
page = null
// ...
constructor(rootStore){
reaction(() => this.uri, uri => this.parseUri(uri))
}
openOverview(){
this.page = { name: "overview", data: { project_id: 1 }}
}
}
decorate(Router, {
uri: observable,
page: observable
})
54
Services & PresentersServices & Presenters
routingrouting
class Router {
uri = "/"
page = null
// ...
constructor(rootStore){
reaction(() => this.uri, uri => this.parseUri(uri))
}
openOverview(){
this.page = { name: "overview", data: { project_id: 1 }}
}
}
decorate(Router, {
uri: observable,
page: observable
}) Where load that data?
Where load that data?
54
Services & PresentersServices & Presenters
view presenterview presenter
class Router {
uri = "/"
page = null
constructor(rootStore){
this.page = this.loadHome()
reaction(() => this.uri, uri => this.parseUri(uri))
}
openOverview(){
this.page = fromPromise(
this.overviewStore.fetchData()
.then(data =>
Promise.resolve({ name: "overview", data })
)
)
}
}
55
Services & PresentersServices & Presenters
view presenterview presenter
class Router {
uri = "/"
page = null
constructor(rootStore){
this.page = this.loadHome()
reaction(() => this.uri, uri => this.parseUri(uri))
}
openOverview(){
this.page = fromPromise(
this.overviewStore.fetchData()
.then(data =>
Promise.resolve({ name: "overview", data })
)
)
}
}
55
Services & PresentersServices & Presenters
fromPromisefromPromise
class Router {
uri = "/"
page = null
constructor(rootStore){
this.page = this.loadHome()
reaction(() => this.uri, uri => this.parseUri(uri))
}
openOverview(){
this.page = fromPromise(
this.overviewStore.fetchData()
.then(data =>
Promise.resolve({ name: "overview", data })
)
)
}
}
56
MobX Async TipsMobX Async Tips
reactive finite state machinesreactive finite state machines
<div>
{ this.page.case({
pending: () => "loading",
rejected: (e) => "error: " + e,
fulfilled: ({name, data}) => {
switch(name){
case "home": return <HomePage data={data} />;
case "overview": return <Overview data={data} />;
}
}
})}
</div>
57
Real-World ArchitectureReal-World Architecture
Current State RecapCurrent State Recap
VIEW
REPOSITORY
Renders the view and
calls actions on the store
Holds domain state
Create and modify domain state
Fetch from API
Holds and modify application state
Implements business logic
SERVICE
DOMAIN MODEL
PRESENTER
Aggregates data for the view
Call actions on the services
58
Today's RecapToday's Recap
59
Today's RecapToday's Recap
1. Use Redux if you're paid by the hour
59
Today's RecapToday's Recap
1. Use Redux if you're paid by the hour
2. Find your minimal state
59
Today's RecapToday's Recap
1. Use Redux if you're paid by the hour
2. Find your minimal state
3. Derive whatever is possible
59
Today's RecapToday's Recap
1. Use Redux if you're paid by the hour
2. Find your minimal state
3. Derive whatever is possible
4. Think as you're building for any UI environment
59
Today's RecapToday's Recap
1. Use Redux if you're paid by the hour
2. Find your minimal state
3. Derive whatever is possible
4. Think as you're building for any UI environment
5. Always experiment and have fun!
59
Want something opinionated?Want something opinionated?
1. Define store shape
2. Automatic serialization/deserialization
3. Implements both a immutable & mutable store
4. Defines a stricter architecture
5. Time travelling
discover mobx-state-treediscover mobx-state-tree
60
Not into mutable things?Not into mutable things?
stay here for the next talk!stay here for the next talk!
61
Thanks for your time!Thanks for your time!
Questions?Questions?
 
@MattiaManzati - slides.com/mattiamanzati
62
ReferencesReferences
 
https://slides.com/mattiamanzati/real-world-
mobx
http://mobx-patterns.surge.sh/
https://medium.com/@mweststrate/ui-as-an-
afterthought-26e5d2bb24d6
https://github.com/mobxjs/mobx
https://github.com/mobxjs/mobx-react
https://github.com/mobxjs/mobx-state-tree
63

Más contenido relacionado

La actualidad más candente

Menu the foundation for control [compatibility mode]
Menu the foundation for control [compatibility mode]Menu the foundation for control [compatibility mode]
Menu the foundation for control [compatibility mode]Rajendra Nabar
 
Haccp for instend cooked rice
Haccp for instend cooked riceHaccp for instend cooked rice
Haccp for instend cooked ricerooshi mk
 
PUBLIC AREA CLEANING
PUBLIC AREA CLEANINGPUBLIC AREA CLEANING
PUBLIC AREA CLEANINGZAIDUL HAQUE
 
Part 1 catering control principles and procedures
Part 1 catering control principles and proceduresPart 1 catering control principles and procedures
Part 1 catering control principles and proceduresDedy Wijayanto
 
Facility planning kitchen layout and planning
Facility planning   kitchen layout and planningFacility planning   kitchen layout and planning
Facility planning kitchen layout and planningvikesh Kashyap
 
The seven functions of catering
The seven functions of cateringThe seven functions of catering
The seven functions of cateringDardar Jumarito
 
Housekeeping - cleaning
Housekeeping  - cleaning Housekeeping  - cleaning
Housekeeping - cleaning Priya Roy
 
planning-work-of-housekeeping-dept.
 planning-work-of-housekeeping-dept. planning-work-of-housekeeping-dept.
planning-work-of-housekeeping-dept.Gautam Kumar
 
Ar6017 urban housing question bank no copy
Ar6017 urban housing question bank no copyAr6017 urban housing question bank no copy
Ar6017 urban housing question bank no copySiva Raman
 
files-and-formats-used-in-housekeeping-departments
 files-and-formats-used-in-housekeeping-departments files-and-formats-used-in-housekeeping-departments
files-and-formats-used-in-housekeeping-departmentsGautam Kumar
 
Year 9 & 10 - First Principles of Food Preparation & Cooking - Food Safety & ...
Year 9 & 10 - First Principles of Food Preparation & Cooking - Food Safety & ...Year 9 & 10 - First Principles of Food Preparation & Cooking - Food Safety & ...
Year 9 & 10 - First Principles of Food Preparation & Cooking - Food Safety & ...Victoria Hansen Enterprises
 

La actualidad más candente (20)

Menu the foundation for control [compatibility mode]
Menu the foundation for control [compatibility mode]Menu the foundation for control [compatibility mode]
Menu the foundation for control [compatibility mode]
 
control desk.pptx
control desk.pptxcontrol desk.pptx
control desk.pptx
 
Haccp for instend cooked rice
Haccp for instend cooked riceHaccp for instend cooked rice
Haccp for instend cooked rice
 
PUBLIC AREA CLEANING
PUBLIC AREA CLEANINGPUBLIC AREA CLEANING
PUBLIC AREA CLEANING
 
Part 1 catering control principles and procedures
Part 1 catering control principles and proceduresPart 1 catering control principles and procedures
Part 1 catering control principles and procedures
 
Facility planning kitchen layout and planning
Facility planning   kitchen layout and planningFacility planning   kitchen layout and planning
Facility planning kitchen layout and planning
 
STORAGE / STOREROOM CONTROL
STORAGE / STOREROOM CONTROLSTORAGE / STOREROOM CONTROL
STORAGE / STOREROOM CONTROL
 
Steward 4th sem
Steward 4th semSteward 4th sem
Steward 4th sem
 
The seven functions of catering
The seven functions of cateringThe seven functions of catering
The seven functions of catering
 
Reimagining the Vertical Farm 2015
Reimagining the Vertical Farm 2015Reimagining the Vertical Farm 2015
Reimagining the Vertical Farm 2015
 
Issuing Control
Issuing ControlIssuing Control
Issuing Control
 
dr. yap
 dr. yap dr. yap
dr. yap
 
01 menage
01  menage01  menage
01 menage
 
Issuing control
Issuing controlIssuing control
Issuing control
 
Housekeeping - cleaning
Housekeeping  - cleaning Housekeeping  - cleaning
Housekeeping - cleaning
 
planning-work-of-housekeeping-dept.
 planning-work-of-housekeeping-dept. planning-work-of-housekeeping-dept.
planning-work-of-housekeeping-dept.
 
Ar6017 urban housing question bank no copy
Ar6017 urban housing question bank no copyAr6017 urban housing question bank no copy
Ar6017 urban housing question bank no copy
 
Table service
Table serviceTable service
Table service
 
files-and-formats-used-in-housekeeping-departments
 files-and-formats-used-in-housekeeping-departments files-and-formats-used-in-housekeeping-departments
files-and-formats-used-in-housekeeping-departments
 
Year 9 & 10 - First Principles of Food Preparation & Cooking - Food Safety & ...
Year 9 & 10 - First Principles of Food Preparation & Cooking - Food Safety & ...Year 9 & 10 - First Principles of Food Preparation & Cooking - Food Safety & ...
Year 9 & 10 - First Principles of Food Preparation & Cooking - Food Safety & ...
 

Similar a Mattia Manzati - Real-World MobX Project Architecture - Codemotion Rome 2019

#FrontConf2017 — Enhance your User (and Developer) Experience with React & Redux
#FrontConf2017 — Enhance your User (and Developer) Experience with React & Redux#FrontConf2017 — Enhance your User (and Developer) Experience with React & Redux
#FrontConf2017 — Enhance your User (and Developer) Experience with React & Reduxphacks
 
Reactive programming with RxJS - Taiwan
Reactive programming with RxJS - TaiwanReactive programming with RxJS - Taiwan
Reactive programming with RxJS - Taiwanmodernweb
 
The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)Scott Wlaschin
 
Hipster oriented programming (Mobilization Lodz 2015)
Hipster oriented programming (Mobilization Lodz 2015)Hipster oriented programming (Mobilization Lodz 2015)
Hipster oriented programming (Mobilization Lodz 2015)Jens Ravens
 
The biggest lies about react hooks
The biggest lies about react hooksThe biggest lies about react hooks
The biggest lies about react hooksMarios Fakiolas
 
Let's discover React and Redux with TypeScript
Let's discover React and Redux with TypeScriptLet's discover React and Redux with TypeScript
Let's discover React and Redux with TypeScriptMathieu Savy
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)Jose Manuel Pereira Garcia
 
React & The Art of Managing Complexity
React &  The Art of Managing ComplexityReact &  The Art of Managing Complexity
React & The Art of Managing ComplexityRyan Anklam
 
State management in a GraphQL era
State management in a GraphQL eraState management in a GraphQL era
State management in a GraphQL erakristijanmkd
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2Leonid Maslov
 
Architecture for scalable Angular applications
Architecture for scalable Angular applicationsArchitecture for scalable Angular applications
Architecture for scalable Angular applicationsPaweł Żurowski
 
Building user interface with react
Building user interface with reactBuilding user interface with react
Building user interface with reactAmit Thakkar
 
README.MD for building the first purely digital mobile bank in Indonesia
README.MD for building the first purely digital mobile bank in Indonesia README.MD for building the first purely digital mobile bank in Indonesia
README.MD for building the first purely digital mobile bank in Indonesia Richard Radics
 
ngSummit 2017: Angular meets Redux
ngSummit 2017: Angular meets ReduxngSummit 2017: Angular meets Redux
ngSummit 2017: Angular meets ReduxMichał Michalczuk
 
From Back to Front: Rails To React Family
From Back to Front: Rails To React FamilyFrom Back to Front: Rails To React Family
From Back to Front: Rails To React FamilyKhor SoonHin
 
Dot Net Accenture
Dot Net AccentureDot Net Accenture
Dot Net AccentureSri K
 
Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?PVS-Studio
 
Knowledge of Javascript
Knowledge of JavascriptKnowledge of Javascript
Knowledge of JavascriptSamuel Abraham
 

Similar a Mattia Manzati - Real-World MobX Project Architecture - Codemotion Rome 2019 (20)

#FrontConf2017 — Enhance your User (and Developer) Experience with React & Redux
#FrontConf2017 — Enhance your User (and Developer) Experience with React & Redux#FrontConf2017 — Enhance your User (and Developer) Experience with React & Redux
#FrontConf2017 — Enhance your User (and Developer) Experience with React & Redux
 
Reactive programming with RxJS - Taiwan
Reactive programming with RxJS - TaiwanReactive programming with RxJS - Taiwan
Reactive programming with RxJS - Taiwan
 
Frontin like-a-backer
Frontin like-a-backerFrontin like-a-backer
Frontin like-a-backer
 
The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)The Functional Programming Toolkit (NDC Oslo 2019)
The Functional Programming Toolkit (NDC Oslo 2019)
 
Google maps
Google mapsGoogle maps
Google maps
 
Hipster oriented programming (Mobilization Lodz 2015)
Hipster oriented programming (Mobilization Lodz 2015)Hipster oriented programming (Mobilization Lodz 2015)
Hipster oriented programming (Mobilization Lodz 2015)
 
The biggest lies about react hooks
The biggest lies about react hooksThe biggest lies about react hooks
The biggest lies about react hooks
 
Let's discover React and Redux with TypeScript
Let's discover React and Redux with TypeScriptLet's discover React and Redux with TypeScript
Let's discover React and Redux with TypeScript
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
React & The Art of Managing Complexity
React &  The Art of Managing ComplexityReact &  The Art of Managing Complexity
React & The Art of Managing Complexity
 
State management in a GraphQL era
State management in a GraphQL eraState management in a GraphQL era
State management in a GraphQL era
 
2. Design patterns. part #2
2. Design patterns. part #22. Design patterns. part #2
2. Design patterns. part #2
 
Architecture for scalable Angular applications
Architecture for scalable Angular applicationsArchitecture for scalable Angular applications
Architecture for scalable Angular applications
 
Building user interface with react
Building user interface with reactBuilding user interface with react
Building user interface with react
 
README.MD for building the first purely digital mobile bank in Indonesia
README.MD for building the first purely digital mobile bank in Indonesia README.MD for building the first purely digital mobile bank in Indonesia
README.MD for building the first purely digital mobile bank in Indonesia
 
ngSummit 2017: Angular meets Redux
ngSummit 2017: Angular meets ReduxngSummit 2017: Angular meets Redux
ngSummit 2017: Angular meets Redux
 
From Back to Front: Rails To React Family
From Back to Front: Rails To React FamilyFrom Back to Front: Rails To React Family
From Back to Front: Rails To React Family
 
Dot Net Accenture
Dot Net AccentureDot Net Accenture
Dot Net Accenture
 
Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?Of complicacy of programming, or won't C# save us?
Of complicacy of programming, or won't C# save us?
 
Knowledge of Javascript
Knowledge of JavascriptKnowledge of Javascript
Knowledge of Javascript
 

Más de Codemotion

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Codemotion
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyCodemotion
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaCodemotion
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserCodemotion
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Codemotion
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Codemotion
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Codemotion
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 - Codemotion
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Codemotion
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Codemotion
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Codemotion
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Codemotion
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Codemotion
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Codemotion
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Codemotion
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...Codemotion
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Codemotion
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Codemotion
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Codemotion
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Codemotion
 

Más de Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Último

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdfChristopherTHyatt
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 

Último (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 

Mattia Manzati - Real-World MobX Project Architecture - Codemotion Rome 2019

  • 1. 1
  • 2. ReduxRedux Raise your hand if you used in production...Raise your hand if you used in production... 2
  • 3. MobXMobX Raise your hand if you used in production...Raise your hand if you used in production... 3
  • 4. React.createContextReact.createContext Do you want to experiment with justDo you want to experiment with just I hope I'll change your idea! I hope I'll change your idea! 4
  • 6. What does anWhat does an application needs?application needs? 6
  • 7. What does anWhat does an application needs?application needs? STORE ITS STATE 6
  • 8. What does anWhat does an application needs?application needs? STORE ITS STATEMODIFY ITS STATE 6
  • 9. What does anWhat does an application needs?application needs? STORE ITS STATEMODIFY ITS STATE VIEW ITS STATE AGGREGATED 6
  • 10. What does anWhat does an application needs?application needs? STORE ITS STATEMODIFY ITS STATE VIEW ITS STATE AGGREGATED PERFORM SIDE EFFECTS 6
  • 19. MobXMobX Reactive library No concept of stream Uses Proxies (ES6+) or Atoms (ES5-) 8
  • 22. ObservablesObservables Store your application state State may change over time ActionsActions 9
  • 23. ObservablesObservables Store your application state State may change over time Observable instance may be the same ActionsActions 9
  • 24. ObservablesObservables Store your application state State may change over time Observable instance may be the same ActionsActions Change observables state value 9
  • 25. ObservablesObservables Store your application state State may change over time Observable instance may be the same ActionsActions Change observables state value Can be triggered from UI or side effects 9
  • 28. ComputedsComputeds Derived state data Automatically updated synchronusly ReactionsReactions 10
  • 29. ComputedsComputeds Derived state data Automatically updated synchronusly Always up to date with current observable state ReactionsReactions 10
  • 30. ComputedsComputeds Derived state data Automatically updated synchronusly Always up to date with current observable state ReactionsReactions Trigger functions when a condition changes 10
  • 31. ComputedsComputeds Derived state data Automatically updated synchronusly Always up to date with current observable state ReactionsReactions Trigger functions when a condition changes UI is a reaction of the store state 10
  • 32. A successful pattern inA successful pattern in history!history! 11
  • 33. 12
  • 34. Excel is Reactive!Excel is Reactive! 13
  • 35. Excel is Reactive!Excel is Reactive! CELLS 13
  • 36. Excel is Reactive!Excel is Reactive! CELLSUSER INTERACTION 13
  • 37. Excel is Reactive!Excel is Reactive! CELLSUSER INTERACTION FORMULAS 13
  • 38. Excel is Reactive!Excel is Reactive! CELLSUSER INTERACTION FORMULAS SCREEN UPDATES 13
  • 39. Let's start!Let's start! A classic example: TODO ListsA classic example: TODO Lists 14
  • 40. class App extends React.Component { // observable values currentText = ""; todos = []; // actions addTodo = () => { this.todos.push({ name: this.currentText, done: false }); this.currentText = ""; }; toggleTodo = todo => { todo.done = !todo.done; }; setCurrentText = text => { this.currentText = text; }; // computed get pendingCount() { return this.todos.filter(todo => !todo.done).length; } // ... } 15
  • 41. class App extends React.Component { // observable values currentText = ""; todos = []; // actions addTodo = () => { this.todos.push({ name: this.currentText, done: false }); this.currentText = ""; }; toggleTodo = todo => { todo.done = !todo.done; }; setCurrentText = text => { this.currentText = text; }; // computed get pendingCount() { return this.todos.filter(todo => !todo.done).length; } // ... } 15
  • 42. class App extends React.Component { // observable values currentText = ""; todos = []; // actions addTodo = () => { this.todos.push({ name: this.currentText, done: false }); this.currentText = ""; }; toggleTodo = todo => { todo.done = !todo.done; }; setCurrentText = text => { this.currentText = text; }; // computed get pendingCount() { return this.todos.filter(todo => !todo.done).length; } // ... } 15
  • 43. class App extends React.Component { // observable values currentText = ""; todos = []; // actions addTodo = () => { this.todos.push({ name: this.currentText, done: false }); this.currentText = ""; }; toggleTodo = todo => { todo.done = !todo.done; }; setCurrentText = text => { this.currentText = text; }; // computed get pendingCount() { return this.todos.filter(todo => !todo.done).length; } // ... } 15
  • 44. class App extends React.Component { // ... // render observer render() { return ( <div className="App"> <h1>TODOs</h1> <input type="text" value={this.currentText} onChange={e => this.setCurrentText(e.target.value)} /> <button onClick={this.addTodo}>Add</button> <ul> {this.todos.map(item => ( <li onClick={() => this.toggleTodo(item)}> {item.name} {item.done ? <i>DONE!</i> : null} </li> ))} </ul> <p>There are {this.pendingCount} pending todos.</p> </div> ); 16
  • 45. class App extends React.Component { // ... // render observer render() { return ( <div className="App"> <h1>TODOs</h1> <input type="text" value={this.currentText} onChange={e => this.setCurrentText(e.target.value)} /> <button onClick={this.addTodo}>Add</button> <ul> {this.todos.map(item => ( <li onClick={() => this.toggleTodo(item)}> {item.name} {item.done ? <i>DONE!</i> : null} </li> ))} </ul> <p>There are {this.pendingCount} pending todos.</p> </div> ); 16
  • 46. class App extends React.Component { // ... } const MyApp = observer(App); decorate(App, { currentText: observable, todos: observable, addTodo: action, toggleTodo: action, setCurrentText: action, pendingCount: computed }); const rootElement = document.getElementById("root"); ReactDOM.render(<MyApp />, rootElement); 17
  • 47. class App extends React.Component { // ... } const MyApp = observer(App); decorate(App, { currentText: observable, todos: observable, addTodo: action, toggleTodo: action, setCurrentText: action, pendingCount: computed }); const rootElement = document.getElementById("root"); ReactDOM.render(<MyApp />, rootElement); 17
  • 48. Few notes:Few notes: Component state managed byComponent state managed by MobX or not?MobX or not? class App extends React.Component { @observable currentText = "" // ... } export default observer(App) class App extends React.Component { state = { currentText: "" } // ... } 18
  • 49. Few notes:Few notes: Component state managed byComponent state managed by MobX or not?MobX or not? class App extends React.Component { @observable currentText = "" // ... } export default observer(App) 19
  • 50. Few notes:Few notes: Component state managed byComponent state managed by MobX or not?MobX or not? Better optimized than setState class App extends React.Component { @observable currentText = "" // ... } export default observer(App) 19
  • 51. Few notes:Few notes: Component state managed byComponent state managed by MobX or not?MobX or not? Better optimized than setState Simpler API than setState class App extends React.Component { @observable currentText = "" // ... } export default observer(App) 19
  • 52. Few notes:Few notes: Component state managed byComponent state managed by MobX or not?MobX or not? Better optimized than setState Simpler API than setState Easier to refactor to a separate store class App extends React.Component { @observable currentText = "" // ... } export default observer(App) 19
  • 53. Few notes:Few notes: Decorators are optionalDecorators are optional class Store { @observable todos = [] } class Store { todos = [] } decorate(Store, { todos: observable }); 20
  • 54. Few notes:Few notes: Classes are optionalClasses are optional class Store { @observable todos = [] } const store = new Store() const store = observable({ todos: [] }) 21
  • 55. MobX is unopinionatedMobX is unopinionated 22
  • 56. MobX is unopinionatedMobX is unopinionated How do I X? 22
  • 57. MobX is unopinionatedMobX is unopinionated How do I X? Should I MVC? 22
  • 58. MobX is unopinionatedMobX is unopinionated How do I X? Should I MVC? Should I MVVM? 22
  • 59. MobX is unopinionatedMobX is unopinionated How do I X? Should I MVC? Should I MVVM? Should I MVP? 22
  • 60. MobX is unopinionatedMobX is unopinionated How do I X? Should I MVC? Should I MVVM? Should I MVP? Should I Flux? 22
  • 61. MobX is aMobX is a reactive data libraryreactive data library 23
  • 63. It works!It works! Does it scales? Does it scales? 24
  • 64. It works!It works! Is it testable? Is it testable? Does it scales? Does it scales? 24
  • 65. It works!It works! Is it testable? Is it testable? Mix BL and UI? Mix BL and UI? Does it scales? Does it scales? 24
  • 66. Don't mix Business Logic & UIDon't mix Business Logic & UI 25
  • 67. Don't mix Business Logic & UIDon't mix Business Logic & UI What if we want a React Native app later? 25
  • 68. Don't mix Business Logic & UIDon't mix Business Logic & UI What if we want a React Native app later? What if UI framework changes? 25
  • 69. Don't mix Business Logic & UIDon't mix Business Logic & UI What if we want a React Native app later? What if UI framework changes? What if we need SSR? 25
  • 70. Don't mix Business Logic & UIDon't mix Business Logic & UI What if we want a React Native app later? What if UI framework changes? What if we need SSR? 25
  • 71. Don't mix Business Logic & UIDon't mix Business Logic & UI class Store { // observable values currentText = ""; todos = []; // actions addTodo = () => { this.todos.push({ name: this.currentText, done: false }); this.currentText = ""; }; toggleTodo = todo => { todo.done = !todo.done; }; setCurrentText = text => { this.currentText = text; }; // computed get pendingCount() { return this.todos.filter(todo => !todo.done).length; } } Extracting the StoreExtracting the Store 26
  • 72. class Store { // ... } class App extends React.Component { // ... } const MyApp = observer(Store); const store = new Store(); const rootElement = document.getElementById("root"); ReactDOM.render(<MyApp store={store} />, rootElement); Don't mix Business Logic & UIDon't mix Business Logic & UI Wiring the Store as propWiring the Store as prop 27
  • 73. import { observer, Provider, inject } from "mobx-react"; // ... const MyApp = inject("store")(observer(App)); const store = new Store(); const rootElement = document.getElementById("root"); ReactDOM.render( <Provider store={store}> <MyApp /> </Provider>, rootElement); Don't mix Business Logic & UIDon't mix Business Logic & UI Use Provider & InjectUse Provider & Inject 28
  • 74. import { observer, Provider, inject } from "mobx-react"; // ... const MyApp = inject("store")(observer(App)); const store = new Store(); const rootElement = document.getElementById("root"); ReactDOM.render( <Provider store={store}> <MyApp /> </Provider>, rootElement); Don't mix Business Logic & UIDon't mix Business Logic & UI Use Provider & InjectUse Provider & Inject No need to pass down manually your stores 28
  • 75. import { observer, Provider, inject } from "mobx-react"; // ... const MyApp = inject("store")(observer(App)); const store = new Store(); const rootElement = document.getElementById("root"); ReactDOM.render( <Provider store={store}> <MyApp /> </Provider>, rootElement); Don't mix Business Logic & UIDon't mix Business Logic & UI Use Provider & InjectUse Provider & Inject No need to pass down manually your stores Allows to change store implementation in your tests 28
  • 76. import { observer, Provider, inject } from "mobx-react"; // ... const MyApp = inject("store")(observer(App)); const store = new Store(); const rootElement = document.getElementById("root"); ReactDOM.render( <Provider store={store}> <MyApp /> </Provider>, rootElement); Don't mix Business Logic & UIDon't mix Business Logic & UI Use Provider & InjectUse Provider & Inject No need to pass down manually your stores Allows to change store implementation in your tests Only one point of store injections into the views 28
  • 77. Real-World ArchitectureReal-World Architecture Current State RecapCurrent State Recap VIEW STORE Renders the view and calls actions on the store Holds and modify domain state Holds and modify application state Implements business logic Fetch from API Implements view actions Aggregates data for the view 29
  • 78. Real-World ArchitectureReal-World Architecture Current State RecapCurrent State Recap VIEW STORE Renders the view and calls actions on the store Holds and modify domain state Holds and modify application state Implements business logic Fetch from API Implements view actions Aggregates data for the view W ay too m uch W ay too m uch things! things! 29
  • 79. Domain StateDomain State WTF is dat?WTF is dat? 30
  • 80. Domain StateDomain State WTF is dat?WTF is dat? Is the domain of your app in our example, of Todo 30
  • 81. Domain StateDomain State WTF is dat?WTF is dat? Is the domain of your app in our example, of Todo Describes the application entities and relations 30
  • 82. Domain StateDomain State WTF is dat?WTF is dat? Is the domain of your app in our example, of Todo Describes the application entities and relations Usually it is persistent and stored somewhere 30
  • 83. Domain StateDomain State WTF is dat?WTF is dat? Is the domain of your app in our example, of Todo Describes the application entities and relations Usually it is persistent and stored somewhere Not tight with the UI 30
  • 84. Domain StateDomain State WTF is dat?WTF is dat? Is the domain of your app in our example, of Todo Describes the application entities and relations Usually it is persistent and stored somewhere Not tight with the UI Highly reusable 30
  • 85. Domain StateDomain State first implementationfirst implementation class Todo { name = ""; done = false; } decorate(Todo, { name: observable, done: observable }); class Store { // ... addTodo = () => { const todo = new Todo(); todo.name = this.currentText; this.todos.push(todo); this.currentText = ""; }; } 31
  • 86. Domain StateDomain State domain actionsdomain actions // domain todo model class Todo { name = ""; done = false; toggle(){ this.done = !this.done } } decorate(Todo, { // ... toggle: action }); Observables should be changed trough actions! So it's a good idea to define dumb actions on our domain model! 32
  • 87. Domain StateDomain State let's be more real!let's be more real! // domain todo model class Todo { name = ""; done = false; user_id = 0; // UHM... is this ok? // ... } // domain user model class User { id = 0 name = "" } 33
  • 88. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } 34
  • 89. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } Normalized 34
  • 90. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } Normalized Object tree 34
  • 91. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } Normalized Object tree Easily serialize 34
  • 92. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } Normalized Object tree Easily serialize Difficult access 34
  • 93. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } Normalized Object tree Easily serialize Difficult access Denormalized 34
  • 94. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } Normalized Object tree Easily serialize Difficult access Denormalized Object graph 34
  • 95. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } Normalized Object tree Easily serialize Difficult access Denormalized Object graph Harder serialization 34
  • 96. Domain StateDomain State tree or graph?tree or graph? // domain todo model class Todo { name = ""; done = false; user_id = 0; // ... } // domain user model class User { id = 0 name = "" } // domain todo model class Todo { name = ""; done = false; user = new User(0, ""); // ... } // domain user model class User { id = 0 name = "" } Normalized Object tree Easily serialize Difficult access Denormalized Object graph Harder serialization Easy access 34
  • 97. Domain StateDomain State good news everyone!good news everyone! 35
  • 98. Domain StateDomain State lets do both!lets do both! // domain todo model class Todo { name = "" done = false user_id = 0 get user(){ return store.getUserById(this.user_id) // <- WTF } set user(value){ this.user_id = value.id } } decorate(Todo, { //... user_id: observable, user: computed }) 36
  • 99. Domain StateDomain State lets do both!lets do both! // domain todo model class Todo { name = "" done = false user_id = 0 get user(){ return store.getUserById(this.user_id) // <- WTF } set user(value){ this.user_id = value.id } } decorate(Todo, { //... user_id: observable, user: computed }) 36
  • 100. Multiple Store CommunicationMultiple Store Communication available pattersavailable patters 37
  • 101. Multiple Store CommunicationMultiple Store Communication available pattersavailable patters Singleton instance & require/import 37
  • 102. Multiple Store CommunicationMultiple Store Communication available pattersavailable patters Singleton instance & require/import Dependency injection framework 37
  • 103. Multiple Store CommunicationMultiple Store Communication available pattersavailable patters Singleton instance & require/import Dependency injection framework Root store pattern 37
  • 104. Multiple Store CommunicationMultiple Store Communication root store patternroot store pattern class RootStore { todoStore = null; fetch = null; apiKey = ""; constructor(fetch, apiKey){ this.fetch = fetch this.apiKey = apiKey this.todoStore = new Store(this) } } class Todo { store = null; constructor(store){ this.store = store } } class Store { rootStore = null; constructor(rootStore){ this.rootStore = rootStore } } 38
  • 105. Multiple Store CommunicationMultiple Store Communication root store patternroot store pattern 39
  • 106. Multiple Store CommunicationMultiple Store Communication root store patternroot store pattern Central point for each store to communicate 39
  • 107. Multiple Store CommunicationMultiple Store Communication root store patternroot store pattern Central point for each store to communicate Strongly typed 39
  • 108. Multiple Store CommunicationMultiple Store Communication root store patternroot store pattern Central point for each store to communicate Strongly typed Works as dependency root Can host environment specific variables 39
  • 109. Multiple Store CommunicationMultiple Store Communication root store patternroot store pattern Central point for each store to communicate Strongly typed Works as dependency root Can host environment specific variables Very easily testable 39
  • 110. Multiple Store CommunicationMultiple Store Communication back to our problemback to our problem // domain todo model class Todo { name = "" done = false user_id = 0 store = null; constructor(store){ this.store = store; } get user(){ return this.store.rootStore .userStore.getUserById(this.user_id) } set user(value){ this.user_id = value.id } } 40
  • 111. Multiple Store CommunicationMultiple Store Communication back to our problemback to our problem import { observer, Provider, inject } from "mobx-react"; // ... const MyApp = inject("store")(observer(App)); const store = new RootStore(window.fetch); const rootElement = document.getElementById("root"); ReactDOM.render( <Provider store={store}> <MyApp /> </Provider>, rootElement); 41
  • 112. Multiple Store CommunicationMultiple Store Communication back to our problemback to our problem test("it should restore data from API", async t => { const fakeFetch = () => Promise.resolve({ data: [{id: 1, name: "Mattia"}] }) const store = new RootStore(fakeFetch) await store.userStore.fetchAll() t.equal(store.userStore.users[0].name, "Mattia") }) 42
  • 113. Real-World ArchitectureReal-World Architecture Current State RecapCurrent State Recap VIEW STORE Renders the view and calls actions on the store Holds domain state Create and modify domain state Holds and modify application state Implements business logic Fetch from API Aggregates data for the view DOMAIN MODEL 43
  • 114. Real-World ArchitectureReal-World Architecture Current State RecapCurrent State Recap VIEW STORE Renders the view and calls actions on the store Holds domain state Create and modify domain state Holds and modify application state Implements business logic Fetch from API Aggregates data for the view DOMAIN MODEL 43
  • 115. Domain Model SerializationDomain Model Serialization turning JSON into observablesturning JSON into observables 44
  • 116. Domain Model SerializationDomain Model Serialization turning JSON into observablesturning JSON into observables Our state is an object tree 44
  • 117. Domain Model SerializationDomain Model Serialization turning JSON into observablesturning JSON into observables Our state is an object tree Unfortunately it's not a plain JS object 44
  • 118. Domain Model SerializationDomain Model Serialization turning JSON into observablesturning JSON into observables Our state is an object tree Unfortunately it's not a plain JS object Most APIs provide JSON as intermediate language 44
  • 119. Domain Model SerializationDomain Model Serialization turning JSON into observablesturning JSON into observables Our state is an object tree Unfortunately it's not a plain JS object Most APIs provide JSON as intermediate language We need to provide conversions to serialize or deserialize our state 44
  • 120. Domain Model SerializationDomain Model Serialization deserializationdeserialization class Todo { // ... constructor(store, data){ this.store = store if(data) Object.assign(this, data) } } 45
  • 121. Domain Model SerializationDomain Model Serialization serializationserialization class Todo { // ... get toJSON(){ return { name: this.name, done: this.done } } } // ... decorate(Todo, { toJSON: computed }) JSON is just another view of the domain model, so we can just derive itderive 46
  • 122. Domain Model SerializationDomain Model Serialization packagespackages class User { @serializable(identifier()) id = 0; @serializable name = ''; } class Todo { @serializable name = ''; @serializable done = false; @serializable(object(User)) user = null; } // You can now deserialize and serialize! const todo = deserialize(Todo, { name: 'Hello world', done: true, user: { id: 1, name: 'Mattia' } }); const todoJSON = serialize(todo) with serializr you get that with tagging your domain models 47
  • 123. Domain Model SerializationDomain Model Serialization the deserialization problemthe deserialization problem class TodoStore { todos = [] fromCache(){ const cachedData = localStorage.getItem("todos") || "[]" this.todos = JSON.parse(cachedData) .map(data => new Todo(this, data) } getById = id => this.todos .find(item => item.id === id) } decorate(TodoStore, { fromCache: action }) deserializing is memory intensive! 48
  • 124. MobX hidden featureMobX hidden feature _interceptReads_interceptReads import {_interceptReads} from "mobx" const todos = observable.map() _interceptReads(todos, value => value + "! LOL") todos.set(1, "Mattia") console.log(todos.get("1")) // => Mattia! LOL undocumented (yet there since 2017) mobx feature allows to transform mobx values while reading available for objects, arrays, maps and boxed values 49
  • 125. MobX hidden featureMobX hidden feature _interceptReads to the rescue!_interceptReads to the rescue! class TodoStore { todos = [] _cache = {} constructor(rootStore){ this.rootStore = rootStore // ... _interceptReads(this.todos, this.unboxTodo) } unboxTodo = data => { if(this._cache[data.id]){ return this._cache[data.id] } this._cache[data.id] = new Todo(this, data) return this._cache[data.id] } } 50
  • 126. MobX PerformanceMobX Performance better performant domain storesbetter performant domain stores 51
  • 127. MobX PerformanceMobX Performance better performant domain storesbetter performant domain stores Use ES6 Maps and lookup by ID when possible 51
  • 128. MobX PerformanceMobX Performance better performant domain storesbetter performant domain stores Use ES6 Maps and lookup by ID when possible Store JSON in an observable map 51
  • 129. MobX PerformanceMobX Performance better performant domain storesbetter performant domain stores Use ES6 Maps and lookup by ID when possible Store JSON in an observable map Use _interceptReads to perform lazy deserialization 51
  • 130. MobX PerformanceMobX Performance better performant domain storesbetter performant domain stores Use ES6 Maps and lookup by ID when possible Store JSON in an observable map Use _interceptReads to perform lazy deserialization Implement ID -> name without deserialization 51
  • 131. Real-World ArchitectureReal-World Architecture Current State RecapCurrent State Recap VIEW REPOSITORY Renders the view and calls actions on the store Holds domain state Create and modify domain state Fetch from API Holds and modify application state Implements business logic Aggregates data for the view STORE DOMAIN MODEL 52
  • 132. Real-World ArchitectureReal-World Architecture Current State RecapCurrent State Recap VIEW REPOSITORY Renders the view and calls actions on the store Holds domain state Create and modify domain state Fetch from API Holds and modify application state Implements business logic Aggregates data for the view STORE DOMAIN MODEL 52
  • 133. class Overview { rootStore = null currentText = "" constructor(rootStore){ this.rootStore = rootStore } get todos(){ // perform sorting and pagining here return this.rootStore.todoStore.todos } handleAddClicked(){ this.rootStore.todoStore.addTodo(this.currentText) this.currentText = "" } } decorate(Router, { todos: computed, currentText: observable, handleAddClicked: action }) 53
  • 134. Services & PresentersServices & Presenters routingrouting class Router { uri = "/" page = null // ... constructor(rootStore){ reaction(() => this.uri, uri => this.parseUri(uri)) } openOverview(){ this.page = { name: "overview", data: { project_id: 1 }} } } decorate(Router, { uri: observable, page: observable }) 54
  • 135. Services & PresentersServices & Presenters routingrouting class Router { uri = "/" page = null // ... constructor(rootStore){ reaction(() => this.uri, uri => this.parseUri(uri)) } openOverview(){ this.page = { name: "overview", data: { project_id: 1 }} } } decorate(Router, { uri: observable, page: observable }) Where load that data? Where load that data? 54
  • 136. Services & PresentersServices & Presenters view presenterview presenter class Router { uri = "/" page = null constructor(rootStore){ this.page = this.loadHome() reaction(() => this.uri, uri => this.parseUri(uri)) } openOverview(){ this.page = fromPromise( this.overviewStore.fetchData() .then(data => Promise.resolve({ name: "overview", data }) ) ) } } 55
  • 137. Services & PresentersServices & Presenters view presenterview presenter class Router { uri = "/" page = null constructor(rootStore){ this.page = this.loadHome() reaction(() => this.uri, uri => this.parseUri(uri)) } openOverview(){ this.page = fromPromise( this.overviewStore.fetchData() .then(data => Promise.resolve({ name: "overview", data }) ) ) } } 55
  • 138. Services & PresentersServices & Presenters fromPromisefromPromise class Router { uri = "/" page = null constructor(rootStore){ this.page = this.loadHome() reaction(() => this.uri, uri => this.parseUri(uri)) } openOverview(){ this.page = fromPromise( this.overviewStore.fetchData() .then(data => Promise.resolve({ name: "overview", data }) ) ) } } 56
  • 139. MobX Async TipsMobX Async Tips reactive finite state machinesreactive finite state machines <div> { this.page.case({ pending: () => "loading", rejected: (e) => "error: " + e, fulfilled: ({name, data}) => { switch(name){ case "home": return <HomePage data={data} />; case "overview": return <Overview data={data} />; } } })} </div> 57
  • 140. Real-World ArchitectureReal-World Architecture Current State RecapCurrent State Recap VIEW REPOSITORY Renders the view and calls actions on the store Holds domain state Create and modify domain state Fetch from API Holds and modify application state Implements business logic SERVICE DOMAIN MODEL PRESENTER Aggregates data for the view Call actions on the services 58
  • 142. Today's RecapToday's Recap 1. Use Redux if you're paid by the hour 59
  • 143. Today's RecapToday's Recap 1. Use Redux if you're paid by the hour 2. Find your minimal state 59
  • 144. Today's RecapToday's Recap 1. Use Redux if you're paid by the hour 2. Find your minimal state 3. Derive whatever is possible 59
  • 145. Today's RecapToday's Recap 1. Use Redux if you're paid by the hour 2. Find your minimal state 3. Derive whatever is possible 4. Think as you're building for any UI environment 59
  • 146. Today's RecapToday's Recap 1. Use Redux if you're paid by the hour 2. Find your minimal state 3. Derive whatever is possible 4. Think as you're building for any UI environment 5. Always experiment and have fun! 59
  • 147. Want something opinionated?Want something opinionated? 1. Define store shape 2. Automatic serialization/deserialization 3. Implements both a immutable & mutable store 4. Defines a stricter architecture 5. Time travelling discover mobx-state-treediscover mobx-state-tree 60
  • 148. Not into mutable things?Not into mutable things? stay here for the next talk!stay here for the next talk! 61
  • 149. Thanks for your time!Thanks for your time! Questions?Questions?   @MattiaManzati - slides.com/mattiamanzati 62