本文說明:mobx v5.0.0^、mobx一些基本概念、mobx與react 一塊兒使用的技巧、mobx在使用時注意點javascript
它就是簡單的、可擴展的狀態管理。 由於經過透明的函數響應式編程(transparently applying functional reactive programming - TFRP)使得狀態管理變得簡單和可擴展。java
若是不習慣用裝飾器,用一些經常使用的函數方法也能夠,本文只是寫我的以爲的最佳實踐,但後面項目實現時會實踐。react
// 無 mobx
class TodoList extends Component {
state = { //組件數據只能在state裏,更改只能用setState()
inputItem: "",
listFlag: "all",
allList: []
};
handleInputItem = e => {
this.setState({
inputItem: e.target.value
});
};
handleItemStatus = (e, index) => {
e.persist();
let items = this.state.allList;
console.log(items, index);
items[index].isCompleted = e.target.checked;
this.setState({
allList: items
});
};
...
render(){
...
<input
className="new-todo"
placeholder="What needs to be done?"
value={this.state.inputItem}
onChange={this.handleInputItem}
onKeyDown={this.handleAddItem}
autoFocus={true}
/>
...
<li
className={item.isCompleted ? "completed" : ""}
className={item.isEditing ? "editing" : ""}
key={index}
onDoubleClick={() => {
this.handleItemEdit(index, true);
}}
>
<div className="view">
<input
className="toggle"
type="checkbox"
checked={item.isCompleted}
onChange={e => {
this.handleItemStatus(e, index);
}}
/>
<label>{item.title}</label>
<button
className="destroy"
onClick={() => {
this.handleItemDelete(index);
}}
/>
</div>
<input
className="edit"
value={item.title}
onChange={e => {
this.handleItemTitle(e, index);
}}
onBlur={e => {
this.handleItemEdit(index, false);
}}
/>
</li>
...
}
...
}
複製代碼
// 有 mobx 並且使用裝飾器語法
@observer // 將組件變得可觀察
class TodoListMobx extends Component {
@observable inputItem = ""; // 將屬性變成可觀察屬性
@observable listFlag = "all";
@observable allList = [];
@action // 此操做會引發可觀察屬性的變化
handleInputItem = e => {
console.log(e.target);
this.inputItem = e.target.value; // 直接修改可觀察屬性
console.log(this.inputItem);
};
@action
handleItemToggle = (e, index) => {
e.persist();
this.allList[index].isCompleted = e.target.checked;
};
...
render(){ // 可觀察的組件當其包含的可觀察屬性變化後,render會再次執行。
...
<li
className={LiClass}
key={index}
onDoubleClick={() => {
item.isEdit = true;
}}
>
<div className="view">
<input
className="toggle"
type="checkbox"
checked={item.isCompleted}
onChange={e => {
item.isCompleted = !item.isCompleted;
}}
/>
<label>{item.title}</label>
<button
className="destroy"
onClick={e => {
this.handleItemDelete(index);
}}
/>
</div>
<input
className="edit"
value={item.title}
onChange={e => {
item.title = e.target.value;
}}
onBlur={e => {
item.isEdit = false;
}}
/>
</li>
...
}
...
}
複製代碼
以上兩組代碼對比能夠看到:mobx的加入將react組件裏的數據變化操做簡單化,機動化渲染UI。並且,總體代碼書寫上簡單很多,並且理解上更容易。git
使用裝飾器的代碼仍是參考第一組的第二塊代碼github
// 有 mobx 並且 不使用裝飾器語法
class TodoListMobxNoDeco extends Component {
inputItem = "";
listFlag = "all";
allList = [];
handleInputItem = e => {
console.log(e.target);
this.inputItem = e.target.value;
console.log(this.inputItem);
};
handleItemToggle = (e, index) => {
e.persist();
this.allList[index].isCompleted = e.target.checked;
};
...
render(){ // 可觀察的組件當其包含的可觀察屬性變化後,render會再次執行。
...
<li
className={LiClass}
key={index}
onDoubleClick={() => {
item.isEdit = true;
}}
>
<div className="view">
<input
className="toggle"
type="checkbox"
checked={item.isCompleted}
onChange={e => {
item.isCompleted = !item.isCompleted;
}}
/>
<label>{item.title}</label>
<button
className="destroy"
onClick={e => {
this.handleItemDelete(index);
}}
/>
</div>
<input
className="edit"
value={item.title}
onChange={e => {
item.title = e.target.value;
}}
onBlur={e => {
item.isEdit = false;
}}
/>
</li>
...
}
...
}
decorate(TodoListMobxNoDeco, {
inputItem: observable,
allList: observable,
listFlag: observable,
handleAddItem: action,
handleClearCompleted: action,
handleInputItem: action,
handleItemDelete: action,
handleItemToggle: action,
handleListChg: action
});
TodoListMobxNoDeco = observer(TodoListMobxNoDeco);
export default TodoListMobxNoDeco;
複製代碼
能過這一組例子對比會發現,裝飾器只是一個語法糖,能夠完成不使用,但使用後,可以讓代碼整潔很多。編程
import DevTools from "mobx-react-devtools";
...
render(){return (
<div> <DevTools /> </div>
)}
...
//Counter組件,簡單展現
@observer
class Counter extends Component {
@observable count = 0; // 將count變成可觀察屬性
countCopy = this.count; // 被賦值給一個本地變量,不會隨着this.count的變化而變化
constructor(props) {
super(props);
}
render() {
return (
<div> <span>這是 @observable 變量 count:{this.count}</span> <br /> <span>這是 @observable 變量 count的本地拷貝:{this.countCopy}</span> <br /> <span onClick={this.handleAdd}>Count加一</span> <br /> <span onClick={this.handleDec}>Count減一</span> </div>
);
}
@action
handleAdd = () => {
this.count++;
};
@action
handleDec = () => {
this.count--;
};
}
複製代碼
能夠看到拷貝出來的變量不會再變化app
// 這個例子中,父組件在使用子組件時直接賦值了整個observable,導到若是此Observable地址不變,子組件極有可能不會從新渲染
class SubCounter extends Component {
render() {
const count=this.props.count;
return (
<div> <span> 這是子組件顯示父組件 @observable 變量 countObj.count1: {count.count1} </span> <br /> <span> 這是子組件顯示父組件 @observable 變量 countObj.count1: {count.count2} </span> </div>
);
}
}
@observer
class Counter extends Component {
@observable count = 0;
countCopy = this.count;
@observable countObj = {
count1: 1,
count2: 2
};
constructor(props) {
super(props);
}
render() {
const countCopy2 = this.count;
return (
<div> // 這裏直接引用了整個observable,導到若是此Observable地址不變,子組件極有可能不會從新渲染 <SubCounter count={this.countObj} /> <span> 這是 @observable 變量 countObj.count2:{this.countObj.count2} </span> <br /> <span>這是 @observable 變量 count的本地拷貝:{this.countCopy}</span> <br /> <span onClick={this.handleAdd}>CountObj.count1加一</span> <br /> <span onClick={this.handleDec}>Count減一</span> </div> ); } @action handleAdd = () => { this.countObj.count1++; }; @action handleDec = () => { this.count--; }; } export default Counter; 複製代碼
@observer //若是注掉,那麼不會監視傳過來的count, 天然不會從新渲染
class SubCounter extends Component {
render() {
return (
<div> <span> 這是子組件顯示父組件 @observable 變量 countObj.count1: {this.props.count.count1} </span> <br /> <span> 這是子組件顯示父組件 @observable 變量 countObj.count1: {this.props.count.count2} </span> </div>
);
}
}
@observer
class Counter extends Component {
@observable count = 0;
countCopy = this.count;
@observable countObj = {
count1: 1,
count2: 2
};
constructor(props) {
super(props);
}
render() {
const countCopy2 = this.count;
return (
<div> <SubCounter count={this.countObj} /> <span> 這是 @observable 變量 countObj.count2:{this.countObj.count2} </span> <br /> <span>這是 @observable 變量 count的本地拷貝:{this.countCopy}</span> <br /> <span onClick={this.handleAdd}>CountObj.count1加一</span> <br /> <span onClick={this.handleDec}>Count減一</span> </div> ); } @action handleAdd = () => { this.countObj.count1++; }; @action handleDec = () => { this.count--; }; } export default Counter; 複製代碼