mobx是一个简单可扩展的状态管理库
mobx学习成本更低,性能更好的的状态解决方案
状态变化引起的副作用应该被自动触发
create-vite
npm install mobx mobx-react --save
observable
observable
就是一种让数据的变化可以被观察的方法import { observable } from 'mobx';
const p1 = observable([1, 2, 3]);
p1.push(4);
p1.pop();
console.log(p1);
console.log(Array.isArray(p1));
类型 | 描述 |
---|---|
String | 字符串 |
Boolean | 布尔值 |
Number | 数字 |
Symbol | 独一无二的值 |
import { observable } from 'mobx';
let num = observable.box(10);
let str = observable.box('hello');
let bool = observable.box(true);
console.log(num.get(), str.get(), bool.get());
num.set(100);
str.set('world');
bool.set(false);
console.log(num.get(), str.get(), bool.get());
import { observable } from 'mobx';
class Store {
@observable name='zfpx';
@observable age=9;
@observable isMarried=false;
@observable hobbies=[];
@observable home={name:'北京'};
@observable skills=new Map();
}
let {observable,computed} = require('mobx');
class Store {
@observable name='zfpx';
@observable age=9;
@observable area='010';
@observable number="18910092296"
@observable province="广东";
@observable city="东莞";
@computed get home() {
return this.province+this.city;
}
}
let store=new Store();
let cell = computed(function () {
return store.area+'-'+store.number;
});
cell.observe(change=>console.log(change));
console.log(cell.get());
store.area='020';
store.number='15718856132';
console.log(cell.get());
console.log(store.home);
store.province='山东';
store.city='济南';
console.log(store.home);
autorun(() => {
//console.log(store.province,store.city);
console.log(store.home);
});
store.province='山东';
store.city='济南';
predicate
,直到返回true。 when(predicate: () => boolean, effect?: () => void, options?)
let dispose = when(() => store.age>=18,()=>{
console.log('你已经成年了!')
});
dispose();
store.age=10;
store.age=20;
store.age=30;
autorun
的变种,autorun
会自动触发,reaction
对于如何追踪observable
赋予了更细粒度的控制autorun
的是当创建时效果 函数不会直接运行,只有在数据表达式首次返回一个新值后才会运行reaction(() => [store.province,store.city],arr => console.log(arr.join(',')));
store.province='山东';
store.city='济南';
autorun
和reaction
执行let {observable,computed,autorun,when,reaction,action} = require('mobx');
class Store {
@observable province="广东";
@observable city="东莞";
@action moveHome(province,city) {
this.province=province;
this.city=city;
}
}
let store=new Store();
reaction(() => [store.province,store.city],arr => console.log(arr.join(',')));
store.moveHome('山东','济南');
let {observable,computed,autorun,when,reaction,action} = require('mobx');
class Store {
@observable province="广东";
@observable city="东莞";
@action.bound moveHome(province,city) {
this.province=province;
this.city=city;
}
}
let store=new Store();
reaction(() => [store.province,store.city],arr => console.log(arr.join(',')));
let moveHome=store.moveHome;
moveHome('山东','济南');
runInAction(() => {
store.province='山东';
store.city='济南';
});
npm i react react-dom mobx-react -S
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import {observable,action} from 'mobx';
import PropTypes from 'prop-types';
import {observer} from 'mobx-react';
class Store {
@observable number=0;
@action.bound add() {
this.number++;
}
}
let store=new Store();
@observer
class Counter extends Component{
render() {
return (
<div>
<p>{store.number}</p>
<button onClick={store.add}>+</button>
</div>
)
}
}
ReactDOM.render(<Counter/>,document.querySelector('#root'));
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import {observable,action} from 'mobx';
import PropTypes from 'prop-types';
import {observer} from 'mobx-react';
class Store {
@observable counter={number:0};
@action.bound add() {
this.counter.number++;
}
}
let store=new Store();
@observer
class Counter extends Component{
render() {
return (
<div>
<p>{this.props.counter.number}</p>
<button onClick={this.props.add}>+</button>
</div>
)
}
}
ReactDOM.render(<Counter
counter={store.counter}
add={store.add}
/>,document.querySelector('#root'));
import React,{Component,Fragment} from 'react';
import ReactDOM from 'react-dom';
import {observable,action, computed} from 'mobx';
import PropTypes from 'prop-types';
import {observer,PropTypes as ObservablePropTypes} from 'mobx-react';
class Todo{
id=Math.random();
@observable text='';
@observable completed=false;
constructor(text) {
this.text=text;
}
@action.bound toggle() {
this.completed=!this.completed;
}
}
class Store{
@observable todos=[];
@computed get left() {
return this.todos.filter(todo=>!todo.completed).length;
}
@computed get filterTodos() {
return this.todos.filter(todo => {
switch (this.filter) {
case 'completed':
return todo.completed;
case 'uncompleted':
return !todo.completed;
default:
return true;
}
});
}
@observable filter='all';
@action.bound changeFilter(filter) {
this.filter=filter;
console.log(this.filter);
}
@action.bound addTodo(text) {
this.todos.push(new Todo(text));
}
@action.bound removeTodo(todo) {
this.todos.remove(todo);
}
}
@observer
class TodoItem extends Component{
static porpTypes={
todo: PropTypes.shape({
id: PropTypes.number.isRequired,
text: PropTypes.string.isRequired,
completed:PropTypes.bool.isRequired
}).isRequired
}
render() {
let {todo}=this.props;
return (
<Fragment>
<input
type="checkbox"
onChange={todo.toggle}
checked={todo.completed} />
<span className={todo.completed? 'completed':''}>{todo.text}</span>
</Fragment>
)
}
}
@observer
class TodoList extends Component{
static propsTypes={
store: PropTypes.shape({
addTodo:PropTypes.func,
todos:ObservablePropTypes.observableArrayOf(ObservablePropTypes.observableObject)
}).isRequired
};
state={text:''}
handleSubmit=(event) => {
event.preventDefault();
this.props.store.addTodo(this.state.text);
this.setState({text:''});
}
handleChange=(event) => {
this.setState({text:event.target.value});
}
render() {
let {filterTodos,left,removeTodo,filter,changeFilter}=this.props.store;
return (
<div className="todo-list">
<form onSubmit={this.handleSubmit}>
<input placeholder="请输入待办事项" type="text" value={this.state.text} onChange={this.handleChange}/>
</form>
<ul>
{
filterTodos.map(todo => (
<li key={todo.id}>
<TodoItem todo={todo} />
<button onClick={()=>removeTodo(todo)}>X</button>
</li>
))
}
</ul>
<p>
<span>你还有{left}件待办事项!</span>
<button
onClick={()=>changeFilter('all')}
className={filter==='all'?'active':''}>全部</button>
<button onClick={() => changeFilter('uncompleted')}
className={filter==='uncompleted'?'active':''}>未完成</button>
<button
onClick={()=>changeFilter('completed')}
className={filter==='completed'?'active':''}>已完成</button>
</p>
</div>
)
}
}
let store=new Store();
ReactDOM.render(<TodoList store={store}/>,document.querySelector('#root'));
constructor() {
observe(this.todos,change => {
console.log(change);
this.disposers.forEach(disposer => disposer());
this.disposers=[];
for (let todo of change.object) {
this.disposers.push(observe(todo,change => {
this.save();
//console.log(change)
}));
}
this.save();
});
}
spy(event => {
//console.log(event);
})
constructor() {
observe(this.todos,change => {
console.log(change);
this.disposers.forEach(disposer => disposer());
this.disposers=[];
for (let todo of change.object) {
this.disposers.push(observe(todo,change => {
this.save();
//console.log(change)
}));
}
this.save();
});
}
save() {
localStorage.setItem('todos',JSON.stringify(toJS(this.todos)));
}
trace
尽可能晚的解构使用数据
import React,{Component,Fragment} from 'react';
import ReactDOM from 'react-dom';
import {trace,observable,action, computed, observe, spy,toJS} from 'mobx';
import PropTypes from 'prop-types';
import {observer,PropTypes as ObservablePropTypes} from 'mobx-react';
spy(event => {
//console.log(event);
})
class Todo{
id=Math.random();
@observable text='';
@observable completed=false;
constructor(text) {
this.text=text;
}
@action.bound toggle() {
this.completed=!this.completed;
}
}
class Store{
disposers=[];
constructor() {
observe(this.todos,change => {
console.log(change);
this.disposers.forEach(disposer => disposer());
this.disposers=[];
for (let todo of change.object) {
this.disposers.push(observe(todo,change => {
this.save();
//console.log(change)
}));
}
this.save();
});
}
save() {
localStorage.setItem('todos',JSON.stringify(toJS(this.todos)));
}
@observable todos=[];
@computed get left() {
return this.todos.filter(todo=>!todo.completed).length;
}
@computed get filterTodos() {
return this.todos.filter(todo => {
switch (this.filter) {
case 'completed':
return todo.completed;
case 'uncompleted':
return !todo.completed;
default:
return true;
}
});
}
@observable filter='all';
@action.bound changeFilter(filter) {
this.filter=filter;
console.log(this.filter);
}
@action.bound addTodo(text) {
this.todos.push(new Todo(text));
}
@action.bound removeTodo(todo) {
this.todos.remove(todo);
}
}
@observer
class TodoItem extends Component{
static porpTypes={
todo: PropTypes.shape({
id: PropTypes.number.isRequired,
text: PropTypes.string.isRequired,
completed:PropTypes.bool.isRequired
}).isRequired
}
render() {
trace();
let {todo}=this.props;
return (
<Fragment>
<input
type="checkbox"
onChange={todo.toggle}
checked={todo.completed} />
<span className={todo.completed? 'completed':''}>{todo.text}</span>
</Fragment>
)
}
}
@observer
class TodoFooter extends Component{
static propTypes={
};
render() {
trace();
let {left,filter} = this.props.store;
return (
<div>
<span>你还有{left}件待办事项!</span>
<button
onClick={()=>changeFilter('all')}
className={filter==='all'?'active':''}>全部</button>
<button onClick={() => changeFilter('uncompleted')}
className={filter==='uncompleted'?'active':''}>未完成</button>
<button
onClick={()=>changeFilter('completed')}
className={filter==='completed'?'active':''}>已完成</button>
</div>
)
}
}
@observer
class TodoViews extends Component{
render() {
return (
<ul>
{
this.props.store.filterTodos.map(todo => (
<li key={todo.id}>
<TodoItem todo={todo} />
<button onClick={()=>removeTodo(todo)}>X</button>
</li>
))
}
</ul>
)
}
}
@observer
class TodoHeader extends Component{
state={text:''}
handleSubmit=(event) => {
event.preventDefault();
this.props.store.addTodo(this.state.text);
this.setState({text:''});
}
handleChange=(event) => {
this.setState({text:event.target.value});
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input placeholder="请输入待办事项" type="text" value={this.state.text} onChange={this.handleChange}/>
</form>
)
}
}
@observer
class TodoList extends Component{
static propsTypes={
store: PropTypes.shape({
addTodo:PropTypes.func,
todos:ObservablePropTypes.observableArrayOf(ObservablePropTypes.observableObject)
}).isRequired
};
render() {
trace();
return (
<div className="todo-list">
<TodoHeader store={this.props.store}/>
<TodoViews store={this.props.store}/>
<TodoFooter store={this.props.store}/>
</div>
)
}
}
let store=new Store();
ReactDOM.render(<TodoList store={store}/>,document.querySelector('#root'));