Mobx如此简单
栏目: JavaScript · 发布时间: 5年前
内容简介:本文说明:mobx v5.0.0^、mobx一些基本概念、mobx与react 一起使用的技巧、mobx在使用时注意点它就是简单的、可扩展的状态管理。 因为通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。如果不习惯用装饰器,用一些常用的函数方法也可以,本文只是写个人觉得的最佳实践,但后面项目实现时会实践。
本文说明:mobx v5.0.0^、mobx一些基本概念、mobx与react 一起使用的技巧、mobx在使用时注意点
- mobx 是什么呢?为什么要开发出这个库呢?
- mobx 里的一些关键概念联系:actions、state、computed values、reaction
- mobx 常用的一些 API:@observable、@autorun、@when、@computed、@action
- mobx 中调试追踪的工具
- mobx 中哪些地方值得注意
Mobx是什么?
它就是简单的、可扩展的状态管理。 因为通过透明的函数响应式编程(transparently applying functional reactive programming - TFRP)使得状态管理变得简单和可扩展。
主要概念有哪些?
- actions:一些改变状态值(state)的动作。
- state:可观察的状态值
- computed value:根据state,用pure function计算出来的值
- reactions:因state或computed value变化而引起的反应,主要指视图UI重新渲染
常用装饰器
- @observable 将一个变量变得可观察
- @observer 常用于React组件,可监视其render函数里使用的可观察变量,从而作出相应reactions
- @autorun 常用于组件类或store类的constructor里,用来创建实例时,可监视其函数参数里使用的可观察变量,从而作出相应reactions,一般是将函数再执行一遍。
- @when 有条件的@autorun
- @computed 通过可观察变量经过纯函数计算得来的值,使用时才会计算,没有使用时不会去计算
- @action 能改变可观察变量值的操作(一般是函数方法)
如果不习惯用装饰器,用一些常用的函数方法也可以,本文只是写个人觉得的最佳实践,但后面项目实现时会实践。
TodoList 项目实现对比: github.com/peidongGuo/…
第一组:有没有使用Mobx
// 无 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。而且,整体代码书写上简单不少,而且理解上更容易。
第二组:有没有使用装饰器
使用装饰器的代码还是参考第一组的第二块代码
// 有 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; 复制代码
能过这一组例子对比会发现,装饰器只是一个语法糖,可以完成不使用,但使用后,可让代码整洁不少。
一些常用调试追踪 工具 函数,会在下面的实践中使用
- trace
- mobx-react-devtools
- spy
记住以下几点
- mobx 只对observables 属性的引用监视,不会对其值进行监视
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--; }; } 复制代码
可以看到拷贝出来的变量不会再变化
- 尽量晚些引用observables属性的子属性
// 这个例子中,父组件在使用子组件时直接赋值了整个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
@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; 复制代码
以上所述就是小编给大家介绍的《Mobx如此简单》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。