Mobx和Mobx-react:集中式状态管理

一、Mobx

(1) Mobx是一个功能强大,上手非常容易的状态管理工具。
(2) Mobx背后的哲学很简单: 任何源自应用状态的东西都应该自动地获得。只获取与自己相关的数据,不获取无关数据(redux则相反)
(3) Mobx利用getter和setter来收集组件的数据依赖关系,从而在数据发生变化的时
候精确知道哪些组件需要重绘,在界面的规模变大的时候,往往会有很多细粒度更新,提升性能.
二、Mobx与redux

Mobx写法上更偏向于OOP(面向对象)。
对一份数据直接进行修改操作,不需要始终返回一个新的数据。
并非单一store,可以多store。
Redux默认以JavaScript原生对象形式存储数据,而Mobx使用可观察对象

三、mobx安装:npm install mobx@6

四、mobx使用

1.普通数据类型和复杂数据类型使用案例

不加装饰器的话只能处理同步,处理不了异步


import React, { Component } from 'react';
//observable:转换为可观察对象
//autorun:监听
import  { observable,autorun } from 'mobx';

//普通类型数据的监听
var observableNumber=observable.box(99);
var observableName=observable.box("66球");

//第一次加载时执行,之后每次更新都会执行
//autorun更新到才会执行
autorun(()=>{
    console.log(observableNumber.get());
})
autorun(()=>{
    console.log(observableName.get());
})

setTimeout(() => {
    observableNumber.set(100)
}, 2000);
setTimeout(() => {
    observableName.set("溜溜球")
}, 1000);


//对象
var obj=observable.map({
    name:"刘德华",
    age:18
});
autorun(()=>{
    console.log(obj.get('name'));
})
setTimeout(() => {
    obj.set('name','华仔')
}, 3000);
setTimeout(() => {
    obj.set('age',19)
}, 4000);


class App extends Component {
    render() {
        return (
            <div>
                App
            </div>
        );
    }
}

export default App;

 2.es7装饰器语法应用-可以处理异步

①.让vscode编辑器支持es7装饰器语法

点击文件-首选项-搜索experimentaPecorators-勾选

②.让react支持es7装饰器语法

安装:npm i @babel/core @babel/plugin-proposal-decorators @babel/preset-env

创建 .babelrc文件

{
  "presets": [
    "@babel/preset-env"
 ],
  "plugins": [
   [
      "@babel/plugin-proposal-decorators",
     {
        "legacy": true
     }
   ]
 ]
}

创建config-overrides.js

const path = require('path')
const { override, addDecoratorsLegacy } = require('customize-cra')
function resolve(dir) {
  return path.join(__dirname, dir)
}
const customize = () => (config, env) => {
  config.resolve.alias['@'] = resolve('src')
  if (env === 'production') {
    config.externals = {
      'react': 'React',
      'react-dom': 'ReactDOM'
   }
 }
  return config
};
module.exports = override(addDecoratorsLegacy(), customize())

 安装依赖

npm i customize-cra react-app-rewired

修改package.json

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

注意:改完配置文件之后要重启服务器: npm start

3.案例

①.store.js

runInAction :解决异步问题


// observable:转换为可观察对象
// autorun:监听
//runInAction:处理异步
import {observable, configure, action,runInAction} from 'mobx';
import axios from 'axios';
// 严格模式, 必须写action,
// 如果是never,可以不写action,
// 最好设置always, 防止任意地方修改值, 降低不确定性。
configure({enforceActions: "always"})

class Store{
    @observable isTabbarShow=true;
    @observable list=[];
    @observable cityName="深圳";

    @action changeShow(){
        this.isTabbarShow = true
    }
    @action changeHide(){
        this.isTabbarShow = false
    }

    //异步
    @action getCinemaList(){
        axios({
            url:"https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=7406159",
            method:"get",
            headers:{
                'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.0.4","e":"16395416565231270166529","bc":"110100"}',
                
                'X-Host': 'mall.film-ticket.cinema.list'
      
            }
        }).then(res=>{
            // runInAction 解决异步问题
            runInAction(()=>{
                this.list=res.data.data.cinemas
            })
        })
    }
  
}
export default new Store();

②.isTabbarShow应用

app.js中显示isTabbarShow


import React, { Component } from 'react';
import Mrouter from "./router/indexRouter";
import Tabbar from "./component/Tabbar";
import "./App.css";
import {autorun} from "mobx";
import store from "./mobx/store";

export default class App extends Component {
  state={
    isShow:false
  }
  componentDidMount() {
    autorun(()=>{
      console.log(store.isTabbarShow);
      this.setState({
        isShow:store.isTabbarShow
      })
    })
  }
  
  render() {
    return (
      <div>
        <Mrouter>
        {this.state.isShow && <Tabbar></Tabbar>}
        </Mrouter>
      </div>
    )
  }
}

组件中调用方法changeShow和changeHide控制isTabbarShow

import React,{useEffect} from 'react';
import store from '../mobx/store';

export default function Detail(props) {
   useEffect(() => {
    console.log("create创建");
    store.changeHide()
    return () => {
      store.changeShow()
      console.log("cleanup销毁");
    };
   }, []);

  return (
    <div>Detail</div>
  )
}

③.应用

unsubscribe():自定义方法取消订阅,需要手动取消订阅


import React, { useState, useEffect } from "react";
import store from "../mobx/store";
import {autorun} from 'mobx';

export default function Cinemas(props) {
  const [cinemaList, setcinemaList] = useState([]);

  useEffect(() => {
    if(store.list.length === 0){
      store.getCinemaList()
    }
    var unsubscribe=autorun(()=>{
      console.log(store.list);
      setcinemaList(store.list)
  })
    return () => {
      //取消订阅
      unsubscribe()
    };
  }, []);
 

  return (
    <div>
      <div>
        {cinemaList.map((item) => (
          <dl key={item.cinemaId} style={{padding:"10px"}}>
            <dt>{item.name}</dt>
            <dd style={{fontSize:'12px',color:"gray"}}>{item.address}</dd>
          </dl>
        ))}
      </div>
      cinemaList
    </div>
  );
}

五、mobx-react

1.安装:npm install mobx-react@7

(1)react 组件里使用 @observer
observer 函数/装饰器可以用来将 React 组件转变成响应式组件。
(2) 可观察的局部组件状态
@observable 装饰器在React组件上引入可观察属性。而不需要通过 React 的冗长和强制性的 setState 机制来管理。

(3)Provider 组件
它使用了 React 的上下文(context)机制,可以用来向下传递 stores。 要连接到这些 stores,需要传递一个 stores名称的列表给 inject,这使得 stores 可以作为组件的 props 使用。this.props

 2.案例

①.store.js


// observable:转换为可观察对象
// autorun:监听
//runInAction:处理异步
import {observable, configure, action,runInAction} from 'mobx';
import axios from 'axios';
// 严格模式, 必须写action,
// 如果是never,可以不写action,
// 最好设置always, 防止任意地方修改值, 降低不确定性。
configure({enforceActions: "always"})

class Store{
    @observable isTabbarShow=true;
    @observable list=[];
    @observable cityName="深圳";

    @action changeShow(){
        this.isTabbarShow = true
    }
    @action changeHide(){
        this.isTabbarShow = false
    }

    //异步
    @action getCinemaList(){
        axios({
            url:"https://m.maizuo.com/gateway?cityId=110100&ticketFlag=1&k=7406159",
            method:"get",
            headers:{
                'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.0.4","e":"16395416565231270166529","bc":"110100"}',
                
                'X-Host': 'mall.film-ticket.cinema.list'
      
            }
        }).then(res=>{
            // runInAction 解决异步问题
            runInAction(()=>{
                this.list=res.data.data.cinemas
            })
        })
    }
  
}
export default new Store();

②.主入口文件index.js

import App from "./10-mobx/04-router/App";
import {Provider} from "mobx-react";
import store from "./10-mobx/04-router/mobx/store";

const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render( 
  <div className="box">
    <Provider store={store}>
      <App/>
    </Provider>
    </div>
   );

 ③.app.js


import React, { Component } from 'react';
import Mrouter from "./router/indexRouter";
import Tabbar from "./component/Tabbar";
import "./App.css";
import {observer,inject} from "mobx-react";

//mobx-react利用高阶组件构建一个父组件
@inject("store")//注入store
@observer
export default class App extends Component {
  componentDidMount() {
    console.log(this.props.store);//所有store值
  }
  
  render() {
    return (
      <div>
        <Mrouter>
        {this.props.store.isTabbarShow && <Tabbar></Tabbar>}
        </Mrouter>
      </div>
    )
  }
}

④.子页面 .此组件是函数式组件,不用装饰器的写法,用标签的写法<Observer></Observer>,无状态,无需设置取消订阅,会自动取消订阅


import React, { useState, useEffect } from "react";
import store from "../mobx/store";
import {autorun} from 'mobx';
import {Observer} from 'mobx-react';

export default function Cinemas(props) {

  useEffect(() => {
    if(store.list.length === 0){
      store.getCinemaList()
    }
    return () => {
      //取消订阅
    };
  }, []);
 

  return (
    <div>
      <Observer>
      {
        ()=>{
          return <div>
          {store.list.map((item) => (
            <dl key={item.cinemaId} style={{padding:"10px"}}>
              <dt>{item.name}</dt>
              <dd style={{fontSize:'12px',color:"gray"}}>{item.address}</dd>
            </dl>
          ))}
        </div>
        }
      }
      </Observer>
      cinemaList
    </div>
  );
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值