React + MobX 快速上手2

简介: React + MobX 快速上手

三、常用API介绍及用法

1、@observable (定义变量状态)observable 用于定义可观察状态,观测的数据可以是数字、字符串、数组、对象等。

使用@observable定义的变量是可以被修改的,如果是常量或者不可再被修改的变量就可以不用@observable修饰

例:从mobx中引入observable,  import {observable} from 'mobx'; 使用如下:

@observable count: number = 0;
@observable tool: string = "";
sex: string = 'nan';
@observable classCurrentId: string = '';
@observable classDataList: any = [];

注意:被 observable 观测数据的修改是同步的,不像 setState 那样是异步。

2、@observer (观察者被observer修饰的组件,将会根据组件内使用到的被observable修饰的state的变化而自动重新渲染

一般用在修饰类class前面,内部有可观察的变量的话(通过@observable定义的),添加@observer,即可实时观察数据变化,重新render

例:从mobx-react中引入observer,import {observer} from "mobx-react";

如下:只要store中的count变化了,下面这个Timer组件就会重新render,重新更新,这就是@observer的用途

import store from './mobx/store';//引入store
@observer
class Timer extends React.Component {
    render() {
        return (
            <div>{store.count}</div>
        )
    }
};

3、reaction (监听):组件中通过reaction监听store数据变化,变化之后在组件内部作出相关响应

可以监听一个store变量,也可以监听多个store变量,如下所示

监听一个的例子:

// 监听classCurrentId的变化,newClassId为最新的数据
reaction(() => store.mobTest.classCurrentId, (newClassId) => {
    //dosomething
})
// 监听classDataListLength变化, newClassDataList为最新的数据
reaction(() => store.mobTest.classDataListLength, (newClassDataList) => {
    //dosomething
});

监听多个变量例子:

    /**
       监听screenMode和ClassType.type的变化,下面newData为最新数据,可以通过
       newData.mode, newData.type获取最细的数据
    /*
    reaction(() => ({ mode: store.home.screenMode, type: store.ClassType.type }), newData => {
          //doSomething
    })

    4、toJS():将观察者对象转换成正真定义的格式,如将观察者数组转换成数组,将观察者对象转换成对象

    如:在store中定义了一个可修改的变量为数组格式:@observable answerList: any[] = []; 我们在获取最新answerList数据的时候,拿到的不是真正意义上的数组,是被观察着数组,这时候我们必须通过toJS转换一下就可以了

    例子:

      // answerList为store中定义的被观察的数组,使用reaction监听的时候,通过toJS转换成真正的数组
      reaction(() => toJS(store.answer.answerList), newValue => {
          //doSomething
      })

      5、@inject (注入):注入store中的方法和变量,然后组件里就可以直接通过this.props.xxx的方式使用其他store中的变量或方法

      使用inject注入要注意,需要在跟组件将App组件使用Provider包裹,如下

      import { Provider } from 'mobx-react'


        //store为定义的mobx引入的store文件
        class App extends Component{
            render(){
                return(
                    <Provider store={store}>
                        <ToDoApp/>
                    </Provider>
                )
            }
        }

        组件中使用案例:

          import store from '../mobx/store'; //直接引入store
          interface IProps {
            store?: any; //通过App传入的store
          }
          interface IState {
          }
          @inject('store');//注入所有store
          class PokeButton extends React.Component<IProps, IState> {
              //doSomething 组件里面就可以通过 this.props.store.xxx获取任意store数据
          }

          6、@computed (计算属性):使用@computed修饰的方法,内部只要有一个变量变化,就会重新计算,会在依赖的状态发生变化时会重新运行

          注意点:

          computed 值会被缓存:每当读取 computed 值时,如果其依赖的状态或其他 computed 值未发生变化,则使用上次的缓存结果,以减少计算开销。

          computed 值会惰性计算:只有 computed 值被使用时才重新计算值。反之,即使 computed 值依赖的状态发生了变化,但是它暂时没有被使用,那么它不会重新计算。

          例子:

          //store中定义
          @computed get classDataListLength() {
              return this.classDataList.length;
          }

          使用:classDataListLength变化时执行

          // 监听mobx 班级选中列表元素变化
          reaction(() => store.mobTest.classDataListLength, (newClassDataList) => {
              //doSomething
          });

          7、autorun(自定义反应):用于定义响应函数,并在定义时立即执行一次。以后,每当依赖状态发生变化时,autorun 自动重新运行。

          当你想创建一个响应式函数,而该函数本身永远不会有观察者时,可以使用 mobx.autorun。这通常是当你需要从反应式代码桥接到命令式代码的情况,例如打印日志、持久化或者更新UI的代码。当使用 autorun 时,所提供的函数总是立即被触发一次,然后每次它的依赖关系改变时会再次被触发。相比之下,computed(function) 创建的函数只有当它有自己的观察者时才会重新计算,否则它的值会被认为是不相关的。

          经验法则:如果你有一个函数应该自动运行,但不会产生一个新的值,请使用autorun。其余情况都应该使用 computed。Autoruns 是关于 启动效果 (initiating effects) 的 ,而不是产生新的值。如果字符串作为第一个参数传递给 autorun ,它将被用作调试名。

          传递给 autorun 的函数在调用后将接收一个参数,即当前 reaction(autorun),可用于在执行期间清理 autorun。

          就像@observer 装饰器/函数,autorun 只会观察在执行提供的函数时所使用的数据。

          var numbers = observable([1,2,3]);
          var sum = computed(() => numbers.reduce((a, b) => a + b, 0));
          var disposer = autorun(() => console.log(sum.get()));
          // 输出 '6'
          numbers.push(4);
          // 输出 '10'
          disposer();
          numbers.push(5);
          // 不会再输出任何值。`sum` 不会再重新计算。

          8、@action(动作):用于定义状态修改操作

          常用案例:只有通过@action才可以修改store数据

          import {observable, action} from 'mobx';
          class AnswerData {
            @observable currentState: string = '';
            @observable micList: any[] = [];
            @observable teaStatus: string = 'set';
            @observable timer: number = 0;
            timerId: any = null;
            startTimer = () => {
              this.timerId = setInterval(() => {
                this.timer += 1
              }, 1000);
            }
            @action changeState (state: string) {
              this.currentState = state;
            }
            @action setList (l: any[]) {
              this.micList = l;
              this.startTimer();
            }
            @action teaQuizEnd = () => {
              this.teaStatus = 'reStart';
            }
          }
          export const answer = new AnswerData();

          异步操作处理:

          @action 只会对当前运行的函数做出反应,对于一些不在当前函数中调用的回调是无效的,例如 setTimeout 回调、Promisethenasync 语句。这些回调如果修改了状态,也应该用 action 包裹起来。以下方法可处理该问题:

          修改状态的语句用 runInAction 包裹起来,runInAction包裹执行完成之后再修改

          class Store {
              @observable githubProjects = []
              @observable state = "pending" // "pending" / "done" / "error"
              @action
              async fetchProjects() {
                  this.githubProjects = []
                  this.state = "pending"
                  try {
                      const projects = await fetchGithubProjectsSomehow()
                      const filteredProjects = somePreprocessing(projects)
                      // await 之后,再次修改状态需要动作:
                      runInAction(() => {
                          this.state = "done"
                          this.githubProjects = filteredProjects
                      })
                  } catch (error) {
                      runInAction(() => {
                          this.state = "error"
                      })
                  }
              }
          }

          用法:

          action(fn)
          action(name, fn)
          @action classMethod() {}
          @action(name) classMethod () {}
          @action boundClassMethod = (args) => { body }
          @action(name) boundClassMethod = (args) => { body }
          @action.bound classMethod() {}
          @action.bound(function() {})

          注意:action只能影响正在运行的函数,而无法影响当前函数调用的异步操作

          @action createRandomContact () {
              superagent.get('https://randomuser.me/api/').set('Accept', 'application/json')
                .end(action("createRandomContact-callback", (error: any, results: any) => {
                  if (error) {
                    console.error(error);
                  } else {
                    console.log(results)
                  }
              }));
            }

          在 end 中触发的回调函数,被 action 给包裹了,这就很好验证了上面的那句话,action 无法影响当前函数调用的异步操作,而这个回调毫无疑问是一个异步操作,所以必须再用一个 action 来包裹住它,这样程序才不会报错。

          如果你使用 async function 来处理业务,那么我们可以使用 runInAction 这个 API 来解决问题。

          import {observable, action, runInAction} from 'mobx';
          class Store {
            @observable name = '';
            @action load = async () => {
              const data = await getData();
              runInAction(() => {
                this.name = data.name;
              });
            }
          }

          你可以把 runInAction 有点类似 action(fn)() 的语法糖,调用后,这个 action 方法会立刻执行。

          相关文章
          |
          3月前
          |
          前端开发 JavaScript
          使用 MobX 优化 React 代码
          使用 MobX 优化 React 代码
          54 0
          |
          3月前
          |
          存储 JavaScript 开发者
          Mobx+Mobx-React快速上手 简单可扩展的状态管理解决方案
          Mobx+Mobx-React快速上手 简单可扩展的状态管理解决方案
          59 0
          |
          11月前
          |
          存储 前端开发
          React + MobX 快速上手1
          React + MobX 快速上手
          |
          存储 JavaScript 开发者
          Mobx+Mobx-React快速上手 简单可扩展的状态管理解决方案
          Mobx+Mobx-React快速上手 简单可扩展的状态管理解决方案
          81 0
          |
          运维 前端开发
          基于React、Mobx、Webpack 和 React-Router的项目模板。 #88
          基于React、Mobx、Webpack 和 React-Router的项目模板。 #88
          103 0
          |
          JavaScript 前端开发 开发工具
          React中的状态管理---Mobx
          React中的状态管理---Mobx
          143 0
          React中的状态管理---Mobx
          |
          缓存 前端开发 JavaScript
          从hr口中了解react的状态管理库(mobx, recoil), 立马过来学习之mobx
          从hr口中了解react的状态管理库(mobx, recoil), 立马过来学习之mobx
          |
          前端开发 API
          从hr口中了解react的状态管理库(mobx, recoil), 立马过来学习之recoil
          从hr口中了解react的状态管理库(mobx, recoil), 立马过来学习之recoil
          |
          缓存 前端开发 容器
          React 16.x折腾记 - (4) 侧边栏联动Tabs菜单-增强版(结合Mobx)
          简化了代码逻辑和代码量,重写了一遍,执行逻辑和上个版本有所差异;
          317 0
          |
          移动开发 前端开发 JavaScript
          [react-native]mobx (react中全局数据管理库, 可以简单的实现数据的跨组件共享,类似于vue中的vuex)
          [react-native]mobx (react中全局数据管理库, 可以简单的实现数据的跨组件共享,类似于vue中的vuex)