Mobx中文文档
在npx create-react-app katsuki
的基础上安装依赖
路由安装
yarn add react-router-dom --save
Mobx
安装
yarn add mobx --save
yarn add mobx-react --save
安装decorators
即@
依赖配合mobx
使用
npm install --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.json
到package.json
同级目录
jsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"jsx": "react"
},
"exclude": ["node_modules", "build", "config", "scripts"]
}
在./config/webpack.config.js
的alias配置
添加
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
*/
// 根级store
class Store {
constructor(storeConstructors) {
// storeConstructors 所有传入的仓库
/* storeConstructors结构
{
katsuki: ƒ katsuki()
katsukichan: ƒ katsukichan()
}
*/
if (storeConstructors) {
for (const key in storeConstructors) {
// 每个传入的store作为构造函数,往其添加$getStores方法
// 再经过之后的处理就能在当前仓库获取到stores,以调用其它仓库,目前还不能
// 把新的storeInstance实例存入stores
const S = storeConstructors[key]
if (S && typeof S === 'function') {
// 方式1
// const storeInstance = new S()
// Object.defineProperty(storeInstance, '$getStores', {
// value: () => this.stores,
// })
// 方式2
const storeInstance = new S({
$getStores: () => 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
:入口文件,将引入的内容包含
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
observable
:监测的数据,可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射
action
:修改observable
的值,函数逻辑处理
runInAction
:处理异步操作,如需要请求完成后执行的操作
autorun
:监测的observable
值发生变化执行,如改变的observable
值不包含在autorun
中,则不会执行,用于调试
computed
:计算属性,如observable
值做计算处理,不建议在这里写多的逻辑
inject
:将组件连接到提供的 stores
observer
:可观察属性,引用的组件变成响应式组件,能监听到observable
值的变化重新render
,并只会执行componentWillUpdate
和componentDidUpdate
生命周期函数
在上面的基础上继续操作
创建新的Mobx库:src\store\katsukichan.js
import { observable, action, runInAction, autorun, computed } from 'mobx'
class katsukichan {
// 变量
@observable name = 'katsukichan';
@observable salar = 100;
@observable katsukiArr = ['katsuki'];
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, katsukiArr } = this.props.katsukichan
// 从mobx仓库中获取到的数组或对象,是个观察者对象,不是原本的数组或对象形式
// 网络查找基本都是数组进行 split转化为正常数组,但对象就无法处理
console.log('katsukiArr', katsukiArr)
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;
}
mobx仓库获取数组(array)
或对象(object)
时,是一个观察者对象,而不是正常的数组(array)
或对象(object)
,所以进行以下处理。
src\utils\mobx-store.js
修改
/**
* @name Store
* @desc store 构造器
* @author daecrand
*/
import { action, isComputedProp, isObservableProp, set } from 'mobx'
// 根级store
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: () => this.stores,
})
this.stores[key] = storeInstance
}
}
return this.stores
}
}
// store集合
stores = {}
}
// 所有store的基础类
class StoreModule {
constructor({ $getStores }) {
// 初始化时,赋值
this.$getStores = $getStores
}
/**
* @description 用于获取当前stroe模块所在的根级store中的所有子stroe模块
* @description 用法: const {storeA, storeB} = this.$getStores()
*/
$getStores() {}
/**
* @description 用于更新store模块中的值
* @param {object} nextState 需要更新的值,其中的key必须存在于store中
*
* @description 由于此更新方法支持异步,所以不需要在'runInAction'中执行
* @description 用法: this.$set({ a:"", b:0 })
*/
$set(nextState) {
if (typeof nextState !== 'object') {
console.error(new Error('mobx action "$set": 参数类型必须为 "object"'))
return
}
action(state => {
for (const key in state) {
// 这里使用mobx提供的set类似es6的map映射的set,this指当前store
if (isObservableProp(this, key) && !isComputedProp(this, key)) {
set(this, key, state[key])
} else {
console.error(
new Error(
`mobx action "$set": 当前 store 实例中不存在 "${key}", 或者 "${key}" 不是一个可观察属性(observable)`
)
)
}
}
})(nextState)
}
}
export { Store, StoreModule }
src\store\katsukichan.js
使用src\store\katsuki.js
示例
import { observable, action, runInAction, autorun, computed } from 'mobx'
class katsukichan extends StoreModule {
// 变量
@observable name = 'katsukichan';
@observable salar = 100;
@observable katsukiArr = ['katsuki'];
@action
reSetSalar = value => {
// 获取 katsuki仓库
const { katsuki } = this.$getStores()
console.log('age', katsuki.age) // 18
// 更新mobx仓库值
// 设置后的数组为正常数组,对象同理
this.$set({ salar: value, katsukiArr = ['katsukichan'] })
}
export default katsukichan