mobx 5 + react 函数组件 的一些用法,算是学习mobx的一些小总结

因为维护项目的需要,得学习一下mobx,之前用过基于redux封装的dav,但是它的model写起来有点费劲,就像vue一样,条条框框,更改状态要不停的的setxxx,getxxx,但是mobx就简化了很多,只需要添加几个修饰器即可

首先是create-react-app 创建一个项目

 下载mobx ,mobx-react依赖

因为react是不支持修饰符的,所以还得下载支持的插件 @babel/plugin-proposal-decorators customize-cra react-app-rewired @babel/preset-env @babel/core,在根目录下创建config-overrides.js,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())

更改启动配置

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

创建.babelrc文件,代码:

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

配置完后接着就是demo了

  创建store文件,下面有globalStore.js和index.js,todoStor.js

globalStore.js片段:

import {observable,action, makeObservable,makeAutoObservable} from "mobx";

class GlobalStore {
    constructor() {
        makeObservable(this)
    }

    @observable loading = true;
    @observable count = 100;
    @action
    setLoading(flag = false) {
        console.log('aile')
        this.loading = flag;
        this.count += 100
    }
}

export default  GlobalStore;

index.js 片段(将多个modle整合到一起):

 import TodoStore from './todoStore';
import GlobalStore from './globalStore';

let todoStore = new TodoStore();
let globalStore = new GlobalStore();

const stores = {
    todoStore,
    globalStore
}

export default stores;

todoStore.js 片段(没用到):

 import {observable, action, computed,makeObservable} from 'mobx';


const INIT_TODO = {
    id: 1,
    text: 'mobx事例',
    completed: false
}

class TodoStore {

    constructor() {
        makeObservable(this)
    }

    @observable 
    todoList = [INIT_TODO];

    @computed 
    get totalTodos() {
        return this.todoList.length
    }

    @action 
    addTodo(text){
        const newTodo = {
            id: +new Date(),
            text,
            completed: false
        }
        this.todoList = [...this.todoList, newTodo];
    }

    @action
    changeStatus(id) {
        this.todoList = this.todoList.map(item => {
            return item.id === id
            ? {...item, completed: !item.completed}
            : item
        })
    }


    @action 
    delTodo(id){
        this.todoList = this.todoList.filter(item => item.id !== id)
    }

    @action
    clearTodos() {
        this.todoList = [];
    }
}

export default TodoStore;

在pages下创建 两个页面 game和home

game 下的index.js 片段:

 import { useStores } from '../../hooks';
const Game = ()=>{
    let store = useStores();
    const { globalStore }  = store;
    return(
        <>
           <div>game</div>
           <div onClick={()=>{globalStore.setLoading(true)}}>增加数据</div>
           <span>显示的数据 {globalStore.count}</span>
        </>
    )
}

export default Game;

home 下的index.js 片段:



import { useObserver } from 'mobx-react-lite';

import { useStores } from '../../hooks';



const Home = ()=>{
   let store = useStores(); 
   const { globalStore } = store;
    return useObserver(()=>(
      <>
         <div>首页</div>
         <div>我要现实的东西{globalStore.count}</div>
      </>
   ))
}

export default Home;

创建Layout文件夹(index.js index.less),这里我当做是父组件,子组件是game,home

index.js 代码:

 import { Routes, Route, Link, BrowserRouter as Router } from 'react-router-dom';
import { Observer, Provider, useLocalStore, useObserver } from 'mobx-react'
import { useStores } from '../hooks';

import stores from '@/store/index.js'
import Home from '../pages/home'
import Game from '../pages/game'
import './index.css'

const Layout = () => {
    const localStore = useLocalStore(() => stores);
    const { globalStore } = localStore
    return useObserver(() =>(
        <Router>
        <div>
            <Link to={`/`}>首页</Link>
            <Link to={`/game`}>游戏</Link>
            <span>{localStore.globalStore.count}</span>
            <button onClick={()=>{globalStore.setLoading(true)}}>添加</button>
        </div>
        <Routes>
            <Route path='/' element={<Home />} />
            <Route path='/game' element={<Game />} />
        </Routes>
    </Router>
    ))
}
export default Layout;

layout中index.js里的重点!!! 在子组件game中调用globalstore的方法改变count的状态,在layout中没有更新,但是在home组件中是更新的,据说是mobx版本的原因,这里我用useLocalStore解决的

创建contexts文件夹(index.js),用来衔接各个组件的model/store

index.js 代码:

 import React from 'react';
import stores from '../store';

export const StoresContext = React.createContext({
    ...stores
})

创建hooks文件夹(index.js),将衔接的model自定义hooks

index.js 代码:

 import React from 'react'
import { StoresContext } from '../contexts';

export const useStores = () => React.useContext(StoresContext)

最后在入口文件index.js中将layout下的index.js 塞到根目录下

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';

import Layout from './router/index'
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
       <Layout />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

在子组件中也可以用useLocalStore来获取状态,不一定得用自定义hooks,mobx6就不需要修饰器了,现在还没了解,用法再续…勿喷

你可能感兴趣的:(javascript,前端,react.js)