React状态管理——Dva

发布于:2025-07-29 ⋅ 阅读:(34) ⋅ 点赞:(0)

目录

一、安装依赖

二、Dva注册model方式

2.1 自动注册models

2.2 手动注册model方式

三、创建 dva 实例

四、创建 model

五、在组件中使用

六、动态加载Dva Model


Dva 是一个基于 redux 和 redux-saga 的轻量级前端框架,可以方便地在 React 应用中管理状态。下面是将 Dva 接入 create-react-app 项目的步骤:

一、安装依赖

        在react-react-app项目目录中安装 dva 相关依赖:

npm install dva --save
# 或者使用 yarn
yarn add dva

二、Dva注册model方式

2.1 自动注册models

        Dva 本身不会自动识别特定的 models 文件夹或 model.js 文件,但官方推荐以下约定俗成的结构:

src/
  ├── models/          # 全局 model 目录
  │   ├── user.js      # 用户 model
  │   └── product.js   # 产品 model
  └── pages/
      ├── Home/
      │   ├── model.js # 页面级 model (可选)
      │   └── index.js
      └── About/
          ├── model.js
          └── index.js

2.2 手动注册model方式

        Dva 需要显式注册 model 才会生效,主要有以下几种注册方式:

  • 初始化时注册
// src/index.js
app.model(require('./models/user').default);
  • 动态注册
// 在组件或路由加载时
useEffect(() => {
  app.model(require('./models/product').default);
}, []);

三、创建 dva 实例

修改 src/index.js 文件:


import React from 'react';
import dva from 'dva';
import createHistory from 'history/createBrowserHistory';
import App from './App';
import './index.css';

// 1. Initialize
const app = dva({
  history: createHistory(),
});

// 2. Plugins (可选)
// app.use({});

// 3. Model (可以在这里注册全局model)
// app.model(require('./models/example').default);

// 4. Router
app.router(() => <App />);

// 5. Start
app.start('#root');

四、创建 model

在 src/models 目录下创建一个 model 文件,例如 counter.js

// 标准的 model 文件示例 (models/counter.js)
//export default {
//  namespace: 'user',  // 必须的唯一标识
//  state: {},         // 必须的初始状态
//  reducers: {},      // 同步修改 state 的方法
//  effects: {},       // 异步处理逻辑
//  subscriptions: {}  // 订阅数据源
//};


export default {
  namespace: 'counter',
  state: {
    count: 0,
  },
  reducers: {
    add(state) {
      return { ...state, count: state.count + 1 };
    },
    minus(state) {
      return { ...state, count: state.count - 1 };
    },
  },
  effects: {
    *addAsync(_, { call, put }) {
      yield call(delay, 1000);
      yield put({ type: 'add' });
    },
  },
};

function delay(timeout) {
  return new Promise(resolve => {
    setTimeout(resolve, timeout);
  });
}

五、在组件中使用

方法一:connect

import React from 'react';
import { connect } from 'dva';

function Counter({ count, dispatch }) {
  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => dispatch({ type: 'counter/add' })}>+</button>
      <button onClick={() => dispatch({ type: 'counter/minus' })}>-</button>
      <button onClick={() => dispatch({ type: 'counter/addAsync' })}>Add Async</button>
    </div>
  );
}

function mapStateToProps(state) {
  return {
    count: state.counter.count,
  };
}

export default connect(mapStateToProps)(Counter);

方法二:React Hooks(useSelector、useDispatch)

import React from 'react';
import { useSelector, useDispatch } from 'dva';

function Counter() {
  // 使用 useSelector 获取 state 中的 counter 数据
  const count = useSelector(state => state.counter.count);
  
  // 使用 useDispatch 获取 dispatch 方法
  const dispatch = useDispatch();

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => dispatch({ type: 'counter/add' })}>+</button>
      <button onClick={() => dispatch({ type: 'counter/minus' })}>-</button>
      <button onClick={() => dispatch({ type: 'counter/addAsync' })}>Add Async</button>
    </div>
  );
}

export default Counter;

六、动态加载Dva Model

方法一:使用useEffect + app.model()

import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'dva';

export default function CounterPage() {
  const dispatch = useDispatch();
  const count = useSelector(state => state.counter.count);
  
  useEffect(() => {
    // 动态加载 model
    app.model(require('../models/counter').default);
    
    // 组件卸载时取消注册 model(可选)
    return () => {
      app.unmodel('counter');
    };
  }, [app]);

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => dispatch({ type: 'counter/add' })}>+</button>
    </div>
  );
}

方法二:使用dynamic

import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'dva';

export default function CounterPage() {
  const dispatch = useDispatch();
  const count = useSelector(state => state.counter.count);
  
  useEffect(() => {
    // 动态加载 model
    dispatch({
      type: '@@dva/dynamicLoad',
      payload: {
        models: () => [import('../models/counter')],
      },
    });
    
    return () => {
      // 可以在这里取消 model(如果需要)
    };
  }, [dispatch]);

  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => dispatch({ type: 'counter/add' })}>+</button>
    </div>
  );
}

网站公告

今日签到

点亮在社区的每一天
去签到