目录
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>
);
}