zoukankan      html  css  js  c++  java
  • Mobx 学习笔记

    最简单的版本

    第一步:初始化容器仓库

    import {observable} from "mobx"
    class Store
    {
      @observable count = 0;//将普通数据变为可被观测的数据
      
    }
    
    import {observable,action} from "mobx"
    class Store
    {
      @observable count = 0;//将普通数据变为可被观测的数据
      @action.bound increment(){ //添加一个action,修改数据状态
         this.count++
      }
    }
    

    第二步:在组件中使用mobx容器状态

    初始版本

    //1. 定义组件
    class App extends React.Component{
      render(){
        return <div>
          <h1>App Component</h1>
        </div>
      }
    }
    //2. 渲染组件
    ReactDOM.render(<App />,document.getElementById('root'));
    

    第二版 使用状态数据

    //1. 定义组件
    class App extends React.Component{
      render(){
        const {count} = this.props;
        return <div>
          <h1>App Component</h1>
          <p>{store.count}</p>
        </div>
      }
    }
    //2. 渲染组件
    //传递store对象,当做props,这样就可以在render函数中使用了
    ReactDOM.render(<App store= {new Store()}/>,document.getElementById('root'));
    

    第三版 使用action

    //1. 定义组件
    class App extends React.Component{
      render(){
        const {count} = this.props;
        return <div>
          <h1>App Component</h1>
          <p>{store.count}</p>
          <button onClick= {store.increment}> Increment  </button>
        </div>
      }
    }
    //2. 渲染组件
    //传递store对象,当做props,这样就可以在render函数中使用了
    ReactDOM.render(<App store= {new Store()}/>,document.getElementById('root'));
    

    第四版 关联mobx和react

    //1. 定义组件
    import {observer} from "mobx-react"
    @observer  //修改的是这里
    class App extends React.Component{
      render(){
        const {count} = this.props;
        return <div>
          <h1>App Component</h1>
          <p>{store.count}</p>
          <button onClick= {store.increment}> Increment  </button>
        </div>
      }
    }
    //2. 渲染组件
    //传递store对象,当做props,这样就可以在render函数中使用了
    ReactDOM.render(<App store= {new Store()}/>,document.getElementById('root'));
    

    装饰器的种类

    1. 类修饰器

    //不带参数的版本
    function fn(target){ //target为类定义
      target.foo = "bar";
    }
    @fn
    class MyClass {
    
    }
    console.log(MyClass.foo) // => bar
    
    //带参数的版本
    function fn2(value){
      return function(target){
        target.count = value
      }
    }
    @fn2(10)
    class MyClass {
    
    }
    console.log(MyClass.count) // => 10
    

    2. 类实例对象修饰器

    function fn3(target){
      target.prototype.foo= "bar";
    }
    @fn3
    class MyClass {
    
    }
    let obj = new MyClass();
    console.log(MyClass.foo) // => bar
    

    3. 类实例属性修饰器

    function fn4(target,name,descriptor){
      console.log(target);//target为目标类的prototype
      //=> {constructor:f}
      console.log(name);//name 被修饰的类成员名称
      //=> message
      console.log(descriptor);//descriptor 被修饰的类成员的描述对象 
      //=> {configurable:true,enumerable:true,writable:true,initializer:f}
      descriptor.writable = false;//修改为不可写,只读
    }
    class MyClass {
      @fn4 message = "hello";
    }
    

    4. 类实例方法修饰器和类实例属性修饰器是一样的

    function fn4(target,name,descriptor){
      console.log(target);//target为目标类的prototype
      //=> {constructor:f}
      console.log(name);//name 被修饰的类成员名称
      //=> message
      console.log(descriptor);//descriptor 被修饰的类成员的描述对象 
      //=> {configurable:true,enumerable:true,writable:true,initializer:f}
      descriptor.writable = false;//修改为不可写,只读
    }
    class MyClass {
      @fn4 test (){
        console.log("hello");
      }
    }
    

    理解 observable

    状态改变触发事务更新

    import {autorun} from 'mobx'
    //autorun 根据依赖决定观测后的行为处理
    const store = new Store()
    //autorun 一上来会自动执行一次,然后autorun就知道了自己依赖了store.count
    //当store.count发生改变,autorun会自动执行; 这里就要求store.count是可观测的
    //对于不可观测的属性,只会一上来制动执行一次,后续都不会执行,因为观测不到属性的状态修改.
    autorun( 
      ()=>{
        console.log(store.count);
      }
    );
    store.count = 1; //手动修改状态,另外一种方式是通过action
    

    理解computed

    
    @observer
    Class App extends React.Component{
       render()
       {
          return (<p> Total: {store.price * store.count}</p>)
       }
    }
    //该方法的缺点,计算每次渲染都会执行
    //而实际上只需要依赖的数据改变,执行一次即可(缓存起来); 这里是store.price和store.count的数据改变
    
    
    import {computed} from "mobx"
    class Store{
      @observable price = 10;
      @observable count = 5;
      @computed get totalPrice(){
        return this.price * this.count
      }
    }
    @observer
    Class App extends React.Component{
       render()
       {
          return (<p> Total: {store.totalPrice}</p>)
       }
    }
    

    理解action

    //可以手动修改observable属性
    import {computed} from "mobx"
    class Store{
      @observable price = 10;
      @observable count = 5;
      @observable foo = 1;
    }
    const store = new Store();
    autorun( ()=>{
       console.log('autorun:',store.count,store.foo,store.price)
    }
    )
    //autorun 依赖了3个属性,下面的3次修改每一次都会触发一次autorun; 
    store.count = 1;// 这是直接修改的方式 , 触发了一次autorun
    store.foo = 2;//触发了一次autorun
    store.price = 12;//触发了一次autorun
    //如何做到这3个属性的修改,只触发一次autorun呢?类似于数据库中事务的概念
    
    //可以手动修改observable属性
    import {computed} from "mobx"
    class Store{
      @observable price = 10;
      @observable count = 5;
      @observable foo = 1;
      //答案是使用action,然后在函数中修改3个变量; 这样调用change,只会触发一次autorun
      @action change()
      {
        this.count = 2;
        this.price = 12;
        this.foo = 3;
      }
    }
    const store = new Store();
    autorun( ()=>{
       console.log('autorun:',store.count,store.foo,store.price)
    }
    )
    store.change()//这是通过action的修改方式
    

    屏蔽直接修改

    import {configure} from "mobx"
    //修改observed属性时,必须通过action修饰的函数来进行
    configure({
      enforceActions:'observed'
    })
    //直接修改会报错
    store.count = 22; 
    // => changing observed observable values outside actions is not allowd.
    

    action.bound的作用:

    为成员函数绑定this

    class Store{
      @observable price = 10;
      @observable count = 5;
      @observable foo = 1;
      //答案是使用action,然后在函数中修改3个变量; 这样调用change,只会触发一次autorun
      @action change()
      {
        console.log(this);
        this.count = 2;
        this.price = 12;
        this.foo = 3;
      }
    }
    const change = store.change;
    change(); // => 输出undefined,因为对于const change 来说,this的指向window;严格模式为undefined
    

    runInAction 的作用

    可以将多个observable成员变量的数据进行修改,但只触发一次autorun

    import {runInAction} from "mobx"
    runInAction( ()=>{
        store.count = 111;
        store.price = 222;
        store.foo   = 333;
      }
    );
    

    异步action

    class Store{
      @observable price = 10;
      @observable count = 5;
      @observable foo = 1;
    
      @action asyncChange()
      {//默认不允许在异步操作执行对observable数据的修改
       //因为默认行为是异步操作中的动作和action修饰的函数没有任何关系
        setTimeout(()=>{
          this.count = 222;
        },100);
      }
    }
    const store = new Store();
    store.asyncChange(); //会直接报错
    
    class Store{
      @observable price = 10;
      @observable count = 5;
      @observable foo = 1;
    
      //解决异步action方式一,添加新的action函数
      @action.bound changeCount(){
        this.count = 222;
      }
      @action.bound asyncChange()
      {
        setTimeout(this.changeCount(),100); //将回调函数指定为action函数
      }
    }
    const store = new Store();
    store.asyncChange(); //会直接报错
    
    class Store{
      @observable price = 10;
      @observable count = 5;
      @observable foo = 1;
    
      //解决异步action方式二,使用action函数
      @action.bound asyncChange()
      {
        setTimeout(()=>{
          action('changeFoo',()=>{
            this.foo = "hello";
          }) ();//定义一个叫changeFoo的函数,然后立即调用
        },100); 
      }
    }
    const store = new Store();
    store.asyncChange(); //会直接报错
    
    class Store{
      @observable price = 10;
      @observable count = 5;
      @observable foo = 1;
    
      //解决异步action方式三,使用runInAction函数
      @action.bound asyncChange()
      {
        setTimeout(()=>{
          runInAction(()=>{
            this.count = 222;  
          });
        },100); 
      }
    }
    const store = new Store();
    store.asyncChange(); //会直接报错
    

    监测数据的几种方式

    • @computed 前面已经接触过
    • autorun //前面有讲过,一开始会执行一次,然后依赖的数据发生改变,重新出发执行
    • when 条件触发
    • reaction 当被观测的数据发生改变的时候,依次执行第一个函数,将第一个函数的返回值传给第二个函数; 与when的区别,reaction每次修改都会触发;when只执行一次; reaction不会一开始就执行一次
    import {when} from "mobx"
    //当count>100,只执行一次自定义逻辑
    when( ()=>{
      //第一个参数为函数,返回true或者false
      return store.count>100;
    },()=>{ //只有第一个参数的返回值为ture 的时候才执行
      console.log('when:',store.count);
    } )
    
    reaction(
      ()=>{
        //执行一些业务逻辑,返回数据给下一个函数使用
        return store.count
      },
      (data,reaction)=>{//第一个参数为上一个函数的返回值;第二个参数为reaction函数本身
         console.log("reaction :",data);
         //模拟出when的操作
         reaction.dispose();//手动停止当前reaction的监听
      }
    )
    
    

    总结: 只有computed会返回数据,其他的都是用于可观测数据发生改变时,做一些业务逻辑,比如发消息给服务器.
    十分钟入门mobx

  • 相关阅读:
    检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件失败的解决方案--报错80080005
    c# 数组拼接、DataTable拼接
    【C#】数据类型(sbyte,byte,short,ushort,int,uint,long,ulong和char。、、、)
    一个字符占几个字节
    js获取不到scrollTop值的问题
    省市县2020年最新更新
    【警惕流文件转string存数据库操作】记一次数据库异常增长的排查经历
    【VS Code】利用Live Server插件搭建本地服务
    数据库中float类型存储时位数增多问题
    【小工具】阿里云视频上传工具
  • 原文地址:https://www.cnblogs.com/laiqun/p/15376282.html
Copyright © 2011-2022 走看看