Mobx

怎甘沉沦 提交于 2020-01-08 19:23:05

Mobx中文文档

项目搭建

npx create-react-app katsuki的基础上安装依赖

路由安装

yarn add react-router-dom --save

Mobx安装

yarn add mobx --save
yarn add mobx-react --save

@装饰器语法

安装decorators@依赖配合mobx使用

yarn add --save-dev @babel/plugin-proposal-decorators

释放配置文件

npm run eject

出错,提示需要提交,执行下面操作
git add .
git commit -m "katsuki"

修改package.json文件

"babel": {
    "presets": [
      "react-app"
    ],
+    "plugins": [
+      [
+        "@babel/plugin-proposal-decorators",
+        {
+          "legacy": true
+        }
+      ]
+    ]
+  }

建议执行eject后再yarn安装依赖,若先前执行过yarn则要删除整个node_modules重新执行yarn
使用css文件时,需要命名为styles.module.css,因运行eject配置文件发生变化

装饰器调用报错

ctrl+shift+p打开命令,输入Preferences: Open User Settings,在设置中搜索experimentalDecorators,改为true

使用@方式引入文件

添加jsconfig.jsonpackage.json同级目录

jsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "jsx": "react"
  },
  "exclude": ["node_modules", "build", "config", "scripts"]
}

./config/webpack.config.jsalias配置添加

alias: {
+ '@': path.resolve(__dirname, '../src'),
  ...
  ),
}

项目文件修改

src
	pages
		KatsukiPage
			index.jsx
			styles.css
	store
		index.js
		katsuki.js
	utils
		mobx-store.js
	App.js
	index.js

src\utils\mobx-store.js:封装的store集合处理,可在任意文件引入调用store中文件

/**
 * @name Store
 * @desc store 构造器
 * @author daecrand
 */

import { configure } from 'mobx'

// enforceActions严格模式下,不允许在 action 外更改任何状态
configure({ enforceActions: 'observed' })

class Store {
  constructor(storeConstructors) {
    if (storeConstructors) {
      for (const key in storeConstructors) {
        const S = storeConstructors[key]
        if (S && typeof S === 'function') {
          const storeInstance = new S()
          // 注入公共方法'$getStores'
          // 获取所有的'store'
          Object.defineProperty(storeInstance, '$getStores', {
            value: () => this.stores,
          })

          this.stores[key] = storeInstance
        }
      }
      return this.stores
    }
  }

  // store集合
  stores = {}
}

export default Store

src\store\katsuki.js:一个Mobx单文件,可被页面@inject('katsuki')调用

import { observable } from 'mobx'

class katsuki {
    @observable name = 'katsuki';
    @observable age = 18;
}

export default katsuki

src\store\index.js:导入封装文件和各个Mobx单文件,导出,作为rootStore

import Store from '@/utils/mobx-store'
import katsuki from './katsuki'

export default new Store({ katsuki })

src\App.js:配置页面路由

import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom'
import KatsukiPage from '@/pages/KatsukiPage'
import './App.css';

function App() {
  return (
    <>
      <Switch>
        <RouteWithProps exact path="/" component={KatsukiPage} />
        <Redirect to="/" />
      </Switch>
    </>
  );
}

/**
 * @description 接收RouterProps
 * @param {React.ComponentClass} component
 */
function RouteWithProps({ component, ...rest }) {
  const WrapperComponent = component
  return <Route {...rest} render={props => <WrapperComponent {...props} />} />
}

export default App;

src\index.js:入口文件,将引入的内容包含<App />


import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { BrowserRouter } from 'react-router-dom'
import { Provider as MobxProvider } from 'mobx-react'

import App from './App';
import * as serviceWorker from './serviceWorker';

import rootStore from './store'

ReactDOM.render(
    <MobxProvider {...rootStore}>
        <BrowserRouter>
            <App />
        </BrowserRouter>
    </MobxProvider>, 
    document.getElementById('root')
);

serviceWorker.unregister();

src\pages\KatsukiPage\index.jsx:一个调用katsuki库的文件

import React, { Component } from 'react'

import styles from './styles.css'
import { inject, observer } from 'mobx-react'

// 注入多个store模块
// @inject('katsuki', 'katsukichan', ...) 多个引入
@inject('katsuki')

@observer
class Katsuki extends Component {
    
    render() {
        const { name, age } = this.props.katsuki
        return (
            <>
                <div>name:{name}</div>
                <div>age:{age}</div>
            </>
        )
        
    }
}

export default Katsuki

使用

mobx

observable:监测的数据,可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射

action:修改observable的值,函数逻辑处理

runInAction:处理异步操作,如需要请求完成后执行的操作

autorun:监测的observable值发生变化执行,如改变的observable值不包含在autorun中,则不会执行,用于调试

computed:计算属性,如observable值做计算处理,不建议在这里写多的逻辑

mobx-react

inject:将组件连接到提供的 stores

observer:可观察属性,引用的组件变成响应式组件,能监听到observable值的变化重新render,并只会执行componentWillUpdatecomponentDidUpdate生命周期函数

在上面的基础上继续操作
创建新的Mobx库:src\store\katsukichan.js

import { observable, action, runInAction, autorun, computed } from 'mobx'

class katsukichan {
    // 变量
    @observable name = 'katsukichan';
    @observable salar = 100;

	constructor() {
		// 除 observable salar值发生改变触发,其他observable变量改变不触发
        autorun(() => console.log('salar', this.salar))
    }
    
	// 修改observable的函数
    @action
    reSetSalar = value => {
        this.salar = value
    }

    @action
    addSalarSoon = () => {
        this.salar = this.salar + 100
    }

    @action
    addSalarLatter = async () => {
        await delay()
        // 处理异步操作
        runInAction(() => {
            this.salar = this.salar + 1000
        })
    }

	// 展示的observable处理
    @computed get myPoorSalar() {
        return this.name + ' salar: ' + this.salar
    }
}

function delay(ms = 1000) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve()
        },ms)
    })
}

export default katsukichan

导入到导出封装

import Store from '@/utils/mobx-store'
import katsuki from './katsuki'
import katsukichan from './katsukichan'

export default new Store({ katsuki, katsukichan })

创建新的文件引用:src\pages\KatsukiChan\index.jsx

import React, { Component } from 'react'
import styles from './styles.module.css'
import { inject, observer } from 'mobx-react'

@inject('katsuki', 'katsukichan')
@observer
class KatsukiChan extends Component {
    constructor(props) {
        super(props)
        this.props = props
    }

    render() {
        const { age } = this.props.katsuki
        const { name, salar, reSetSalar, addSalarSoon, addSalarLatter, myPoorSalar } = this.props.katsukichan

        return (
            <div className={styles.container}>
                <p className={styles.font_pink}>{name} {age}</p>
                <p className={styles.pointer} onClick={() => reSetSalar(100)}>click to reSet</p>
                <p className={styles.pointer} onClick={addSalarSoon}>click to plus salar now</p>
                <p className={styles.pointer} onClick={addSalarLatter}>click to plus salar latter</p>
                <p>{myPoorSalar}</p>
            </div>
        )
    }
}

export default KatsukiChan

对应样式文件:src\pages\KatsukiChan\styles.module.css

.container {
    width: 1200px;
    margin: 0 auto;
    background-color: gray;
}

.font_pink {
    color: pink;
}

.pointer {
    cursor: pointer;
}

.pointer:hover {
    background-color: pink;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!