mobx——环境搭建

安装mobx

npm i mobx mobx-react --save

配置装饰器

安装扩展react-create-app插件

npm i -D customize-cra react-app-rewired

创建扩展文件

根目录下创建,config-overrides.js
在这里插入图片描述

并如下配置

const { override, addDecoratorsLegacy } = require('customize-cra')
module.exports = override(
    addDecoratorsLegacy()
)

修改package.json的启动脚本
在这里插入图片描述

  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  }

mobx——简单运用

创建存储空间

装饰器形式

import {observable, computed} from "mobx";
class Store{
    constructor(){

    }
    @observable count=0;
    get getCount(){
        return this.count;
    }
    increumnetCount(count){
        this.count=count;
    }
}

export default new Store();

api形式

import {observable, computed} from "mobx";
export default observable({
    count:0,
    increumnetCount:function(count){
        this.count +=count;
    }
});

组件同时相应

类组件响应

只需要在组件上@observer一下,就会自动将与MoxStore相关的位置自动完成视图刷新

import { render } from "@testing-library/react"
import React, { useState, useReducer } from "react"
import { observer } from 'mobx-react';
import MoxStore from "../function/MoxStore"
@observer
class MoxDemo extends React.Component {
    render() {
        return (
            <div>
                <button onClick={() => {
                    MoxStore.increumnetCount(1)
                }}>+</button>
                <div> 父组件:{MoxStore.count}</div>
                <Child></Child>
            </div>
        )
    }
}
@observer
class Child extends React.Component {
    render() {
        return (
            <div>
                <div>子组件:{MoxStore.count}</div>
                <ChildChild></ChildChild>
            </div>
        )
    }
}
@observer
class ChildChild extends React.Component {
    render() {
        return (
            <div>
                <div>子子组件:{MoxStore.count}</div>
            </div>
        )
    }
}
export default MoxDemo

函数组件响应

只需要通过observer 包装一下react的函数组件即可

import { render } from "@testing-library/react"
import React, { useState, useReducer } from "react"
import { observer } from 'mobx-react';
import MoxStore from "../function/MoxStore"
function MoxDemo(){
    return (
        <div>
            <button onClick={() => {
                MoxStore.increumnetCount(1)
            }}>+</button>
            <div> 父组件:{MoxStore.count}</div>
            <Child></Child>
        </div>
    )
}
function Child(){
    return (
        <div>
            <div>子组件:{MoxStore.count}</div>
            <ChildChild></ChildChild>
        </div>
    )
}
function ChildChild(){
    return (
        <div>
            <div>子子组件:{MoxStore.count}</div>
        </div>
    )
}
export default observer(MoxDemo)

mobx——通过observable封装数据

observable——数据类型大全

对象类型
(1)直接创建对象

缺点:只能全局监听该对象,不能针对属性来进行监听

import {observable, computed} from "mobx";
export default observable({
    count:0,
    increumnetCount:function(count){
        this.count +=count;
    }
});

(2)配置创建对象

让指定原有的字段受到观察

import {observable, computed,extendObservable,decorate} from "mobx";
const store={
    count:0,
    increumnetCount:function(count){
        this.count +=count;
    }
}
decorate(store,{
    count:observable
})

export default store;

(3)扩展原有对象

动态扩展指定的字段,并让其受到观察

const store={
    count:0,
    increumnetCount:function(count){
        this.count +=count;
    }
}
extendObservable(store,{
    count:0
})

export default store;

数组类型

var todos = observable([
    { title: "Spoil tea", completed: true },
    { title: "Make coffee", completed: false }
]);
/*
 数组中所有的变化都会赋予了observable,递归实现的都会导致数据响应式更新,除非设置了deep是false
 */
todos[0].completed = false;
todos[2] = { title: 'Take a nap', completed: false };
todos.shift();

在这里插入图片描述

map类型

observable(new Map())
@observable map = new Map()

(1)map中被监听的ES6属性在这里插入图片描述
(2)map中被监听的mobx扩展的属性
在这里插入图片描述

observable——装饰器大全

JSX 元素、DOM 元素、像 History、window 这样的原生对象,等等。 对于这类对象,只需要存储引用而不用把它们转变成 observable

class Message {
    /*
     虚构的例子,如果 author 是不可变的,我们只需要存储一个引用,不应该把它变成一个可变的 observable 对象
     */
    @observable.ref author = null
}

@computed

动态监听指定字段的外部修改和内部修改

class OrderLine {
    @observable price = 0;
    @observable amount = 1;

    constructor(price) {
        this.price = price;
    }
    /*
      当某些监听属性变化时激活对外听得数据整体
     */
    @computed get total() {
        return this.price * this.amount;
    }
    /*
       当total发生变化时激活set方法反向修改……
     */
     set total(total) {
        this.price = total / this.amount // 从 total 中推导出 price
    }
}

observable——box

/*
  创建box observable.box("Vienna")
  	 box observable.box("Vienna",{deep:false})————————————取消深度监听
  获取box boxData.get()
  监听box boxData.observe(function(change){change.oldValue.change.newValue}
  更新box boxData.set("Amsterdam");
 */
const boxData = observable.box("Vienna");
console.log(boxData.get());
boxData.observe(function(change) {
    console.log(change.oldValue, "->", change.newValue);
});
boxData.set("Amsterdam");

mobx——响应数据的函数

autorun

一单被观察者发生变化就调用回调函数

autorun——观察回调

import { render } from "@testing-library/react"
import React, { useState, useReducer} from "react"
import { observer} from 'mobx-react';
import MoxStore from "../function/MoxStore"

import {autorun} from "mobx";
function MoxDemo(){
    autorun(()=>{
        console.log(MoxStore.count)
    })
    return (
        <div>
            <button onClick={() => {
                MoxStore.increumnetCount(1)
            }}>+</button>
            <div> 父组件:{MoxStore.count}</div>
            <Child></Child>
        </div>
    )
}

autorun——onError异常回调捕获

import { render } from "@testing-library/react"
import React, { useState, useReducer } from "react"
import { observer } from 'mobx-react';
import MoxStore from "../function/MoxStore"

import { autorun } from "mobx";
function MoxDemo() {
    autorun(() => {
        console.log(MoxStore.count)
        if (MoxStore.count > 5) {
            throw new Error("Age should not be negative")
        }},
        {
            onError(e) {
                window.alert("Please enter a valid age")
            }
        })
    return (
        <div>
            <button onClick={() => {
                MoxStore.increumnetCount(1)
            }}>+</button>
            <div> 父组件:{MoxStore.count}</div>
            <Child></Child>
        </div>
    )
}

when

条件函数,当发生被观察对象发生改变时,然后第一个校验函数成立返回true,则执行回调函数
一般来讲需要设计一个开关被执行过后了则这个回调不会继续执行

import React, { useState, useReducer } from "react"
import { observer } from 'mobx-react';
import {when} from "mobx";
import MoxStore from "../function/MoxStore"
let flag=true
function MoxDemo() {
    when(
        ()=> MoxStore.count >5&&flag,
        ()=>{alert('数量超过5啦');flag=false}
    );
    return (
        <div>
            <button onClick={() => {
                MoxStore.increumnetCount(1)
            }}>+</button>
            <div> 父组件:{MoxStore.count}</div>
            <Child></Child>
        </div>
    )
}

reaction

对象字段监听

只要对象中指定属性发生变化,才进行回调函数

reaction(
    () => counter.count,
    (count, reaction) => {
        console.log("reaction 3: invoked. counter.count = " + count);
        reaction.dispose();//取消函数,则函数回调执行了一次监听
    }
);

数组长度监听

const todos = observable([
    {
        title: "Make coffee",
        done: true,
    },
    {
        title: "Find biscuit",
        done: false
    }
]);
const reaction1 = reaction(
    () => todos.length,
    length => console.log("reaction 1:", todos.map(todo => todo.title).join(", "))
);

数组字段监听

返回数组中的一个指定字段的数组

const todos = observable([
    {
        title: "Make coffee",
        done: true,
    },
    {
        title: "Find biscuit",
        done: false
    }
]);const reaction2 = reaction(
    () => todos.map(todo => todo.title),
    titles => console.log("reaction 2:", titles.join(", "))
);

action

标记在会对数据发生改变的地方,让MobX你可以在代码中显式地标记出动作所在的位置进而对于调试程序带来方便
开启“严格模式”,需要强制使用 action,不允许在 action 外更改任何状态
configure({ enforceActions: “observed” })

class Ticker {
    @observable tick = 0
    @action
    increment() {
        this.tick++ // 'this' 永远都是正确的
    }
}

对于一些异步操作也同样容器,标记一下函数名然后调用

   action("fetchSuccess", projects => {
                const filteredProjects = somePreprocessing(projects)
                this.githubProjects = filteredProjects
                this.state = "done"
   })

利用mobx替代setState

import {observer} from "mobx-react"
import {observable} from "mobx"

@observer class Timer extends React.Component {
    @observable secondsPassed = 0

    componentWillMount() {
        setInterval(() => {
            this.secondsPassed++
        }, 1000)
    }

    render() {
        return (<span>Seconds passed: { this.secondsPassed } </span> )
    }
}

mobx——inject(上下文注入响应对象)

父级

import React from "react"
import MoxStore from "../function/MoxStore"
import { observer,Provider,inject } from 'mobx-react'
@observer
class MoxDemo extends React.Component {
    render() {
        return (
            <div>
                <button onClick={() => {
                    MoxStore.increumnetCount(1)
                }}>+</button>
                <div> 父组件:{MoxStore.count}</div>
                <Provider MoxStore={MoxStore}>
                    <Child></Child>
                </Provider>
            </div>
        )
    }
}

所有子级

@inject("MoxStore")
@observer//将context的指定数据,绑定在props中更方便使用
class Child extends React.Component {
    render() {
        return (
            <div>
                <div>子组件:{this.props.MoxStore.count}</div>
                <ChildChild></ChildChild>
            </div>
        )
    }
}

@inject("MoxStore")//将context的指定数据,context绑定在props中更方便使用
@observer
class ChildChild extends React.Component {
    render() {
        return (
            <div>
                <div>子子组件:{this.props.MoxStore.count}</div>
            </div>
        )
    }
}

Hooks和注入

React.useContext(MobXProviderContext)可以拿到有Hook注入的整个context对象,然后在其中找到同名MoxStore
再拿出数据,我们自定义了一个Hook完成了这个便捷操作

function useStores() {
    return React.useContext(MobXProviderContext)
  }
function ChildChildChild() {
    const store= useStores()
    return (
        <div>
            <div>子子子组件:{store.MoxStore.count}</div>
        </div>
    )
};

export default MoxDemo
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐