Igor Suvorov
Программист-предприниматель
Занятие 8
8 Apr 2017
Профессия
Node.js & React.js developer
продвинутый курс
TypeScript
ES6
ES5
import { observable, computed, toJS } from "mobx";
import { observer, inject } from "mobx-react";
states, stores
Observable values can be
var myMap = new Map();
var keyString = 'a string',
keyObj = {},
keyFunc = function() {};
// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, 'value associated with keyObj');
myMap.set(keyFunc, 'value associated with keyFunc');
myMap.size; // 3
...
...
myMap.get(keyString); // "value associated with 'a string'"
myMap.get(keyObj); // "value associated with keyObj"
myMap.get(keyFunc); // "value associated with keyFunc"
myMap.get('a string'); // "value associated with 'a string'"
// because keyString === 'a string'
myMap.get({}); // undefined, because keyObj !== {}
myMap.get(function() {}) // undefined, because keyFunc !== function () {}
const int = observable(20);
const str = observable("Some string");
const todos = observable([
{ title: "Spoil tea", completed: true },
{ title: "Make coffee", completed: false }
]);
const person = observable({
// observable properties:
name: "John",
age: 42,
showAge: false,
// computed property:
get labelText() {
return this.showAge ?
`${this.name} (age: ${this.age})` :
this.name;
},
});
temperature.get()
todo.toJS() or todo.slice()
person ???
import { toJS } from 'mobx';
console.log(toJS(null));
console.log(toJS(123));
console.log(toJS(temperature));
console.log(toJS(todos));
console.log(toJS(person));
// Note: this method was named toJSON before MobX 2.2
personJson = {
id: 1,
name: 'Steve Jobs',
};
person = observable(personJson);
personJson = getNewPersonJson();
person = observable(personJson); // bad
??
import { extendObservable } from 'mobx';
extendObservable(person, personJson);
var Person = function(firstName, lastName) {
// initialize observable properties on a new instance
extendObservable(this, {
firstName: firstName,
lastName: lastName
});
}
var matthew = new Person("Matthew", "Henry");
// add a observable property to an already observable object
extendObservable(matthew, {
age: 353
});
class Person {
constructor(props) {
extendObservable(this, props);
}
}
import {
createModelSchema, primitive, reference,
list, object, identifier,
serialize, deserialize
} from "serializr";
class Message { ... }
class User { ... }
// Create model schemas
createModelSchema(Message, {
message : primitive(),
author : reference(User, findUserById),
comments: list(object(Message))
});
const message = deserialize(Message, {
message : "Hello world",
author : 17,
comments: [
{
message: "Welcome!",
author : 23
}
]
});
derivation
const box = observable({
length: 2,
get square() {
return this.length * this.length;
},
set square(value) {
this.length = Math.sqrt(value);
}
});
import {observable, computed} from "mobx";
class OrderLine {
@observable price = 0;
@observable amount = 1;
constructor(price) {
this.price = price;
}
@computed get total() {
return this.price * this.amount;
}
}
import {observable, computed} from "mobx";
var name = observable("John");
var upperCaseName = computed(() =>
name.get().toUpperCase()
);
var disposer = upperCaseName.observe(
change => console.log(change.newValue)
);
name.set("Dave");
// prints: 'DAVE'
observe, observer, autorun, rerender
import { observable } from 'mobx';
const cityName = observable("Vienna");
function printCity() {
console.log(cityName.get());
}
cityName.observe(printCity);
cityName.set("Amsterdam");
cityName.set("London");
var numbers = observable([1,2,3]);
var sum = computed(() => numbers.reduce((a, b) => a + b, 0));
var disposer = autorun(() => console.log(sum.get()));
// prints '6'
numbers.push(4);
// prints '10'
disposer();
numbers.push(5);
var numbers = observable([1,2,3]);
var sum = computed(() => numbers.reduce((a, b) => a + b, 0));
let showSum = false;
var disposer = autorun(() => {
if (showSum) {
console.log(sum.get()
} else {
console.log('showSum === false')
}
}));
// prints 'showSum === false'
showSum = true;
numbers.push(4);
// nothing
numbers.push(5);
// nothing
import {observer} from "mobx-react";
// ---- ES5 syntax ----
const TodoView = observer(React.createClass({
displayName: "TodoView",
render() {
return <div>{this.props.todo.title}</div>
}
}));
// ---- ES6 syntax ----
const TodoView = observer(class TodoView extends React.Component {
render() {
return <div>{this.props.todo.title}</div>
}
})
// ---- ESNext syntax with decorators ----
@observer class TodoView extends React.Component {
render() {
return <div>{this.props.todo.title}</div>
}
}
// ---- or just use a stateless component function: ----
const TodoView = observer(({todo}) => <div>{todo.title}</div>)
class App extends React.Component {
render() {
return (
<div>
{this.props.person.name}
<Observer>
{() => <div>{this.props.person.name}</div>}
</Observer>
</div>
)
}
}
const person = observable({ name: "John" })
React.render(<App person={person} />, document.body)
person.name = "Mike" // will cause the Observer region to re-render
import {observer} from "mobx-react";
@observer class TodoView extends React.Component {
componentWillReact() {
console.log("I will re-render, since the todo has changed!");
}
render() {
return <div>{this.props.todo.title}</div>
}
}
import { PropTypes } from "mobx-react"
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
render() {
const children = this.props.messages.map((message) =>
<Message text={message.text} />
);
return <Provider color="red">
<div>
{children}
</div>
</Provider>;
}
}
@inject("color") @observer
class Button extends React.Component {
render() {
return (
<button style={{background: this.props.color}}>
{this.props.children}
</button>
);
}
}
@inject("color", "user", "theme")
@inject((stores) => ({
myUser: stores.user,
}))
const Button = ({ user, myUser, name }) => (
<div>
{myUser._id === user._id ? <Edit /> : null}
{name}
</div>
);
const EditProfile = inject(
stores => ({
name: stores.user.name,
myUser: stores.user
})
)(Button)
class Box {
@observable width = 10;
@observable height = 5;
@observable length = 2;
@action
add(x = 1) {
this.width += x;
this.height += x;
this.height += x;
}
sub(x = 1) {
this.width -= x;
this.height -= x;
this.height -= x;
}
get volume() {
return this.width * this.height * this.length
}
};
const box = new Box({})
@action /*optional*/ updateDocument = async () => {
const data = await fetchDataFromUrl();
/* required in strict mode to be allowed to update state: */
runInAction("update state after fetching data", () => {
this.data.replace(data);
this.isSaving = true;
})
}
npm install mobx-react-devtools
import DevTools from 'mobx-react-devtools'
const App = () => (
<div>
...
{ __DEV__ && <DevTools /> }
</div>
)
any questions?
программист-предприниматель
By Igor Suvorov
* template