前端学习——Mobx

webpack环境搭建

npm init -y

npm i webpack webpack-cli webpack-dev-server -D

npm i html-webpack-plugin -D

npm i babel-loader @babel/core @babel/preset-env -D

npm i @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D

npm i mobx -S

编写webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    mode: 'development',
    entry: {
        app: path.resolve(__dirname, './src/index.js')
    },
    output: {
        path: path.resolve(__dirname, './dist')
    },
    module: {
        rules: [{
            test: /\.js$/,
            exclude: /node_modules/,
            use: {
                loader:'babel-loader',
                options:{
                    presets:['@babel/preset-env'],
                    plugins:[
                        //支持装饰器
                        ['@babel/plugin-proposal-decorators',{"legacy":true}],
                        // 支持类里面写属性
                        ["@babel/plugin-proposal-class-properties",{'loose':true}],
                        ['@babel/plugin-transform-runtime']
                    ]
                }
            }
        }]
    },
    plugins:[new HtmlWebpackPlugin()],
    // 代码合并方式在一行
    devtool:'inline-source-map'
}

observable可观察对象

import {observable} from 'mobx'

map

set设置,get获取,delete删除,has判断有无

const map = observable.map({a:1,b:2})
map.set('a',11)
console.log(map.get('a'));
console.log(map.get('b'));
map.delete('a')
console.log(map.has('a'));

数组

数组转成可观察的后是proxy,访问和操作与js相同

const arr = observable([1,2,3,4,5])
// arr是一个proxy
console.log(arr[2]);
arr.pop()
arr.push(12)
console.log(arr);

对象

对象转成可观察的后是proxy

let obj = observable({a:1,b:2})
console.log(obj);//obj是一个proxy

基础类型

枚举,布尔值,字符串需要放入box,使用get访问,使用set设置

枚举

 const num = observable.box(10)
 console.log(num.get());

字符串

const str = observable.box('str')
console.log(str.get());

布尔值

const bool = observable.box(true)
console.log(bool.get());

observable装饰器

对 observables 作出响应

autorun

检测数据变化,数据必须是可观察的

参数是一个回调函数

第一次运行会调用,回调函数被引用的数据有变化会调用

用于检测回调函数里对象的变化

let obj = observable({title:'msg'})
autorun(()=>{
    console.log(obj.title);
})
obj.title = 'mmm'

when

有两个参数,都是回调函数,第一个回调函数返回布尔值,为true才运行第二个回调函数

when(
    ()=>{
        return store.bool
    },
    ()=>{
        console.log('when function run...');
    }
)

reaction

autorun的变种

基于某个数据实现视图更新

两个参数,均为回调函数,第一个回调函数的返回值作为第二个回调函数的输入

和autorun的区别:第一次不会调用,发生变化时调用

reaction(
    ()=>{
        return store.str
    },
    (arr)=>{
        console.log(arr.join('/'));
    }
)
setTimeout(() => {
    store.bool = true,
    store.str = 'world'
    store.num = 220
}, 5000);

computed

定义方法:

1.computed函数(使用不多)

对观察的结果可以使用observer方法

const rs = computed(()=>{
    return store.str+store.num
})
console.log(rs.get());
rs.observe((change)=>{
    console.log(rs.get());  
})

store.bool = true,
store.str = 'world'
store.num = 220

2.装饰器定义computed

@computed
    get result(){
        return this.str+this.num
    }
//使用reaction检测变化
reaction(
    ()=>{
        return store.result
    },
    (result)=>{
        console.log(result);
    }
)

改变observable的状态

action

mobx中引入action对象,通过装饰器装饰函数

@action
    bar(){
        this.str = 'mobx',
        this.num = '232'
    }
store.bar()

绑定this

 @action.bound foo(){
        this.str = 'foo'
    }

异步操作

npm i @babel/runtime @babel/plugin-transform-runtime

在webpackconfig.js里配置

@action
    async fzz(){
        console.log('fzz');
        let obj = await new Promise((reslove)=>{
            setTimeout(() => {
                reslove({
                    num:1234,
                    str:'wowo'
                }
                )
            }, 4000);
        })
        runInAction(()=>{
            store.num = obj.num
            store.str = obj.str
        })
        console.log(store.num,store.str);
    }

在react中使用mobx

npx create-react-app react-mobx-app

create-react-app不支持装饰器

二次配置webpack的方法:cra,rewied,eject

yarn eject
npm i @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D

在package.json里配置babel

"babel": {
    "presets": [
      "react-app"
    ],
    "plugins":[
      ["@babel/plugin-proposal-decorators",{"legacy":true}],
      ["@babel/plugin-proposal-class-properties",{"loose":true}]
    ]
  }
npm i mobx mobx-react -S 
yarn start

注意:vscode编译器中,js文件使用装饰器会报红。解决方式:

在根目录编写写jsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "experimentalDecorators": true
  },
  "include": ["src/**/*"]
}

React + Mobx 案例

创建store/index.js

import {observable, action, computed,runInAction} from 'mobx'
class AppStore{
    @observable
    title = 'mobx'
    @observable
    todos = []

    @computed
    get desc(){
        return `一共${this.todos.length}条`
    }
    @action.bound
    addTodo(todo){
        //可以直接操作数据
        this.todos.push(todo)
    }
    @action.bound
    delTodo(){
        this.todos.pop()
    }
    @action.bound
    resetTodo(){
        this.todos = []
    }
    @action.bound
    //异步操作方法1
    // asyncAddTodo(todo){
    //     this.todos.push(todo)
    // }
    //异步操作方法2
    async asyncAddTodo(todo){
        await new Promise((resolve)=>{
            setTimeout(() => {
               resolve() 
            }, 1000);
        })
        runInAction(()=>{
            this.todos.push(todo)
        })
    }

}
const store = new AppStore()
//导出类的实例
export default store

创建pages/Home.js,在这里使用store

import React, { Component } from 'react'
import {observer,inject} from 'mobx-react'
import store from '../store'
//观察者observer:类被引用后,属性发生变化,重新渲染类
// inject可以传入参数,
// 类可以响应变化,根据变化做出渲染或修改数据
@inject('store')
@observer
class Home extends Component {
    addTodo=(item)=>{
        return()=>{
            store.addTodo(item)
        }
    }
    delTodo=()=>{
        store.delTodo()
    }
    resetTodo=()=>{
        store.resetTodo()
    }
    asyncAddTodo=(item)=>{
        return ()=>{
            setTimeout(() => {
                store.asyncAddTodo(item)
            }, 2000);
        }
    }
    render() {
        return (
            <>
            <div>
                {store.title}
            </div>
            <button onClick = {this.addTodo('这是一条内容')}>add</button>
            <button onClick = {this.delTodo}>delete</button>
            <button onClick = {this.resetTodo}>reset</button>
            <button onClick = {this.asyncAddTodo('这是一条异步添加内容')}>async add</button>
            <h6>{store.todos.length}</h6>
            {
                store.todos.map((item,index)=>{
                    return(
                        <div key = {index}>{item}</div>
                    )
                })
            }
            </>
        )
    }
}
export default Home
n onClick = {this.resetTodo}>reset
            
            
{store.todos.length}
{ store.todos.map((item,index)=>{ return(
{item}
) }) } ) } } export default Home


你可能感兴趣的:(前端学习——Mobx)