1、Dva全局架构
使用dva的脚手架,如果不使用的话,也是很简单的npm模块,并建立架构就可以更新使用
dva官网脚手架
.
├── mock // mock数据文件夹
├── node_modules
├── public
├── src
│ ├── assets
│ ├── components // 组件
│ ├── models // dva最重要的文件夹,所有的数据交互及逻辑都写在这里
│ ├── routes // 就是react中主要页面
│ ├── services // 放请求借口方法的文件夹
│ ├── utils
│ ├── index.css
│ ├── index.js // 入口文件
│ └── router.js // 项目的路由文件
├── .roadhogrc.js
├── .roadhogrc.mock.js
└── package.json
2、Dva 入口文件index.js
import dva from 'dva';
import './index.css';
import createLoading from 'dva-loading';
// 1、创建 dva 实例
const app = dva();
// 2、装载插件 (可选)
app.use(createLoading());
// 3、注册 Model(所有model都必须注册)
pp.model(require('./models/example').default);
// 4、配置路由
app.router(require('./router').default);
// 5、启动应用
app.start('#root');
在 src/index.js 里,dva 一共做了以下几件事:
- 从 ‘dva’ 中引入 dva:import dva from ‘dva’;
- 引入全局样式文件:import ‘./index.css’;
- 通过函数生成一个 app 对象:const app = dva();
- 加载插件:ap心·p.use({});
- 注入 model:app.model(require(’./models/example’).default);
- 添加路由:app.router(require(’./router’).default);
- 启动项目:app.start(’#root’);
在这 7 步当中,dva 完成了使用 React 解决 view 层、redux 管理 model、saga 解决异步 的主要功能。
注册多Model简写
使用 webpack 的 require.context 来初始化多个 model。如果使用了这个写法就不用每次新建了model后去入口文件中注册model
1、在model文件夹下创建一个index.js这个index会获取除了本身的这个index.js其他所有model,然后统一导出:
const context = require.context("./",false,/\.js$/);
export default context.keys().filter((item)=>{
return item !== "./index.js"
}).map((key)=>{
return context(key);
})
2、在入口文件的index.js中注册 Model:
import dva from 'dva';
import './index.css';
const app = dva();
app.use({});
// Model 下面也是采用遍历key获取到所有的model,避免了臃肿的代码
require('./models').default.foreach(key => app.model(key.default))
// app.model(require('./models/example').default);
// app.model(require('./models/a').default);
// app.model(require('./models/b').default);
// app.model(require('./models/c').default);
// app.model(require('./models/d').default);
app.router(require('./router').default);
app.start('#root');
3、流程代码
- 1、请求都放在service文件夹下,可以安需求分多个api.js文件
// src/service/api.js
import request from '../utils/request'; //工具类中的自定义请求
export function getData(params = {}) {
return request('/api/data',params);
}
- 2、models文件夹下建立不同的model
1、namespace
官网解释:当前 Model 的名称。整个应用的 State,由多个 Model 的 State 以
namespace
为 key 合成的。官网解释很绕,通俗的说:就是给每个 Model 一个命名用作 key 的标识。一般命名方式等于 Model
js
的 文件名,举个例子:Model 文件
home.js
里namespace
值可以设为:home
2、state
该 Model 当前的状态。每个 Model 的数据都保存在这里,这里的数据通过 Route 视图层的
this.props
,直接显示在页面上。这里的数据一改变,页面上的数据也将自动改变。
3、reducers
用来处理同步操作。如果不需要调接口时候,我们前台传递的
action
(不懂的小伙伴不着急,下面有微讲解) 可以直接调用reducers
里的方法。上面说的同步是同步什么呢?同步该 Model 里面的
state
的数据。打开项目中 models
example.js
。找到reducers
,我将他复制在下方,来讲解一下怎么创建 reducers 下的方法。reducers: { save1(state, action) { return { ...state, ...action.payload }; }, save2(state, action) { return { ...state, ...action.payload }; }, }, 12345678
(1)、save
save
:为一个普通方法的命名,可自行取名(2)、state
state
:为当前 Model 下的所有state
值,可以console.log(state)
看一下输出就知道了。(3)、action
action
:当前台页面需要进行数据操作时,就会创建一个action
,action
存放了传递过来需要对当前state
进行改变的数据。(4)、payload
payload
:就是action
里传递过来的数据。可以console.log(action.payload)
看一下输出就知道了。(5)、return
return
:返回的是新的state
。等于舍弃了旧的state
,重新return
一个新的state
作为当前 Model 的state
。一般情况下,我们要解开旧的
state
,将它重新赋值给新的state
。...state
为 ES6 语法。将操作完成得数据累加到
return
中。同名的数据会覆盖,所以不用担心旧的
state
值会影响到新设置的值。不同名的数据会追加。
4、effects
用来处理异步操作。如果需要调取接口的话,前台页面就需要调用
effects
里的方法。将数据取出来,在传递给
reducers
里的方法进行数据操作和同步state
。来看看例子:
import { querySomething } from '@/services/api'; *query({ payload }, { call, put, select }) { const data = yield call(querySomething, payload); console.log(data) yield put({ type: 'save1', payload: { name: data.text }, }); }, 12345678910
(1)、*
*
:这个*
符号,可能小伙伴们不熟悉,简单点,不管它,只要记住每个effects
里方法前面都加上*
即可。稍微解释一下:
这表明它是一个异步函数,里面可以使用
yield
等待其他异步函数执行结果。(2)、query
query
:方法名,自定义命名。不多解释。(3)、payload
payload
:当前台页面需要进行数据操作时,就会创建一个action
,action
存放了传递过来需要对当前state
进行改变的数据。
payload
就是存放在action
里面的数据。可以console.log(payload)
看输出的效果。(4)、call
call
:与后台服务端接口进行交互。第一个传参:后台服务器接口对应的名称。第二个参数:入参。
同行的
data
为出参。可以console.log(data)
看输出的效果。(5)、put
put
:用来发出事件,即action
。一般调用reducers
下的方法进行同步数据。
type
:该 Model 层里reducers
下的方法名。
payload
:参数的传递。如此一来。我们就将服务端查出来的数据,传递给
reducers
进行同步数据的操作了。(6)、select
select
:如果我们需要调用到其他 Model 层里面的 state值。那么我们就需要用select
来进行操作。const homeName = yield select(state => state.home);
这样我们就可以取到名为
home
的 Model 层里面的state
数据了。
// src/models/example.js
import { getData } from "../services/api";
export default {
namespace: 'example',
state: {},
effects: {
*fetch({ payload }, { call, put }) {
const data = yield call(getData,payload); //发起请求
yield put({ type: 'save',payload:data }); //调用同步方法
},
},
reducers: {
save(state, action) {
return { ...state, action.payload };
},
},
};
- 3、组件中使用connect链接store,并通过props中的dispatch发送action
//组件调用Model方法
import { connect } from 'dva';
function Home(props) {
useEffect(()=>{
const { dispatch } = this.props;
dispatch ({
type:'example/fetch',
payload:{},
})
},[])
return (
<div>{data}</div>
);
}
const mapStateToProps = (state)=>{
return {
data:state.example
}
}
export default connect(mapStateToProps)(HomePage);