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

文章介绍了如何在React项目中集成和使用MobX进行状态管理,通过create-react-app创建项目,配置Babel支持修饰器,创建store并使用修饰器简化状态更新。同时,文章提到了与Redux和dva的比较,以及在不同组件中同步状态的问题和解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

因为维护项目的需要,得学习一下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就不需要修饰器了,现在还没了解,用法再续…勿喷

<think>我们参考用户的问题和提供的引用内容,来回答如何在React函数组件中使用MobX进行状态管理。 根据引用,我们知道MobX是一个状态管理库,而mobx-react-lite是专门为React函数组件(使用Hooks)设计的轻量级绑定。 步骤: 1. 安装必要的包:mobxmobx-react-lite(或者mobx-react,但用户是函数组件,推荐mobx-react-lite,因为它更轻量且专为函数组件设计)。 2. 创建MobX store(可观察的状态)。 3. 使用Provider将store提供给组件树(在根组件或需要的地方)。 4.函数组件中使用inject(或使用React Context)和observer来连接MobX store,并观察状态变化。 但是,在mobx-react-lite中,我们通常使用Context和Hooks的方式(如useContext)来获取store,同时使用observer包裹组件使其响应状态变化。 具体步骤: 1. 安装: ```bash npm install mobx mobx-react-lite ``` 2. 创建一个store。例如,我们创建一个计数器store: ```javascript // counterStore.js import { makeAutoObservable } from "mobx"; class CounterStore { count = 0; constructor() { makeAutoObservable(this); } increment() { this.count += 1; } decrement() { this.count -= 1; } } export default CounterStore; ``` 3. 创建Context,以便在组件中使用: ```javascript // stores/index.js import { createContext, useContext } from "react"; import CounterStore from "./counterStore"; // 创建Context const StoreContext = createContext(); // 可以创建一个根store,如果有多个store可以在这里组合 const rootStore = { counterStore: new CounterStore(), }; // 创建一个Provider组件 export const StoreProvider = ({ children }) => { return ( <StoreContext.Provider value={rootStore}> {children} </StoreContext.Provider> ); }; // 自定义Hook,用于在组件中获取store export const useStore = () => useContext(StoreContext); ``` 4. 在应用的根节点使用Provider: ```javascript // index.js import React from 'react'; import ReactDOM from 'react-dom'; import { StoreProvider } from './stores'; import App from './App'; ReactDOM.render( <StoreProvider> <App /> </StoreProvider>, document.getElementById('root') ); ``` 5.函数组件中使用store和observer: ```javascript // App.js import React from 'react'; import { observer } from 'mobx-react-lite'; import { useStore } from './stores'; const App = observer(() => { const { counterStore } = useStore(); return ( <div> <h1>Count: {counterStore.count}</h1> <button onClick={() => counterStore.increment()}>+</button> <button onClick={() => counterStore.decrement()}>-</button> </div> ); }); export default App; ``` 这样,当点击按钮时,count值会变化,并且组件会自动重新渲染。 注意: - 使用`observer`包裹组件,这样组件就会响应store中可观察状态的变化。 - 使用`useStore`这个自定义Hook来获取store实例。 另外,根据引用[5],mobx-react-lite是基于React Hook API的轻量级状态管理,所以这种方式是推荐的。 如果不想使用Context,也可以直接在一个模块中导出store实例(单例),然后在组件中直接导入使用,但这样不利于测试和复用。使用Context的方式更灵活,也符合React的推荐做法。 以上就是使用MobXReact函数组件中进行状态管理的基本步骤。 相关问题: 1. MobX中的makeAutoObservable和makeObservable有什么区别? 2.MobX中如何处理异步操作? 3. MobX和Redux在状态管理上有哪些主要区别?</think>在 React 函数组件中使用 MobX 进行状态管理,需遵循以下步骤(基于 mobx-react-lite 库): ### 1. 安装依赖 ```bash npm install mobx mobx-react-lite ``` ### 2. 创建 Store(状态仓库) ```javascript // store/counterStore.js import { makeAutoObservable } from "mobx"; class CounterStore { count = 0; // 状态数据 constructor() { makeAutoObservable(this); // 自动使所有属性和方法可观察 } // Action:修改状态的方法 increment = () => { this.count += 1; }; decrement = () => { this.count -= 1; }; } export default CounterStore; ``` ### 3. 创建 Store 上下文 ```javascript // store/index.js import { createContext, useContext } from "react"; import CounterStore from "./counterStore"; const StoreContext = createContext(null); export const StoreProvider = ({ children }) => { const counterStore = new CounterStore(); return ( <StoreContext.Provider value={{ counterStore }}> {children} </StoreContext.Provider> ); }; // 自定义 Hook 获取 store export const useStore = () => { return useContext(StoreContext); }; ``` ### 4. 在根组件注入 Store ```jsx // index.js import React from "react"; import ReactDOM from "react-dom"; import { StoreProvider } from "./store"; import App from "./App"; ReactDOM.render( <StoreProvider> <App /> </StoreProvider>, document.getElementById("root") ); ``` ### 5.组件中使用状态 ```jsx // App.jsx import { observer } from "mobx-react-lite"; import { useStore } from "./store"; const App = observer(() => { const { counterStore } = useStore(); return ( <div> <h1>计数器: {counterStore.count}</h1> <button onClick={counterStore.increment}>+1</button> <button onClick={counterStore.decrement}>-1</button> </div> ); }); export default App; ``` ### 关键点说明: 1. **`observer` 高阶组件**:包裹组件使其响应状态变化,当可观察数据变更时自动重渲染[^4][^5] 2. **`makeAutoObservable`**:自动将类属性转为可观察状态,方法转为 Action[^3] 3. **Context API**:通过 React Context 全局共享 store[^2] 4. **Actions**:所有状态修改必须通过 `@action` 方法(`makeAutoObservable` 已自动处理)[^1] ### 异步操作处理 ```javascript // store/userStore.js import { makeAutoObservable, runInAction } from "mobx"; class UserStore { data = null; loading = false; constructor() { makeAutoObservable(this); } fetchUser = async (id) => { this.loading = true; try { const res = await fetch(`/api/users/${id}`); const data = await res.json(); // 在 runInAction 中修改状态 runInAction(() => { this.data = data; this.loading = false; }); } catch (error) { runInAction(() => { this.loading = false; }); } }; } ``` ### 优势特点: - 响应式更新:自动追踪状态依赖,精准更新组件[^1][^3] - 极简代码:相比 Redux 减少约 40% 样板代码[^4] - 完美支持 Hooks:专为函数组件优化[^5] - 细粒度更新:仅重渲染依赖变更的组件[^1] > 提示:大型项目建议使用多个领域 store,通过 `RootStore` 统一管理[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值