一,什么是Dva
?
1.由于react
专注于ui
渲染,功能较为单一。在实际开发过程中往往需要许多库的支持,例如用于控制数据状态的redux
和redux-saga
,和用于路由控制的react-router
。
2.dva
是 React
应用框架,将React-Router + Redux + Redux-saga
三个 React
工具库包装在一起,简化了 API
,让开发 React
应用更加方便和快捷。
3.Dva = react-router + rudex + redux-saga
二,Dva
项目创建
1.我们可以使用dva
框架的脚手架(dva-cli
)来创建dva
项目
2.我们可以使用npm
来安装dva-cli
脚手架: npm install dva-cli -g
;
3.安装之后可以使用 dva new
命令来创建一个dva
项目:dva new quickdva
4.使用 npm start
让项目跑起来
三,Dva
项目结构
四,Dva
的API
和项目的入口文件
1.dva
项目有一个入口文件,用于配置整个项目的路由,注册model
,插件使用,和项目的启动,这个入口文件几乎涉及了dva
的所有api
import dva from 'dva';
import './index.less';
import createLoading from 'dva-loading';
// 1. Initialize
export const app = dva(createLoading());
// 2. Plugins
// app.use({});
// 3. Model
// app.model(require('./models/example'));
// 4. Router
app.router(require('./router').default);
// 5. Start
app.start('#root');
2.dva
文件默认抛出了dva
函数,用于创建dva
实例。
(1)该函数接受一个配置对象 dva(opt)
3.dva.use()
: dva
实例的use
方法用于使用插件,和注册hooks
4.dva.modal()
:dva
实例的model
方法接受一个model
对象,用于注册model
5.dva.router()
:dva
实例的router
方法接受一个具有固定格式的函数,用于注册路由表
({history,app})=>{
return <Router history={history}>
<Route path="/" component={App} />
</Router>}
五,dva
输出文件
1.默认输出dva
文件,dva
文件默认抛出了dva
函数用于创建dva
实例,其中dva
文件还抛出了connect
高阶组件,用于将model
的state
包装到组件上。
2.dva/dynamic
,用于动态的加载组件和model
,使用app.model
注册的model
是全局的。
3.dva/fetch
,抛出fetch
,用于异步请求。
4.dva/router
,用于注册路由
五,数据流向
1.数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的。当此类行为会改变数据的时候可以通过 dispatch
发起一个 action
,如果是同步行为会直接通过 Reducers
改变 State
,如果是异步行为(副作用)会先触发 Effects
然后流向 Reducers
最终改变 State
。
2.我们在models
文件夹里定义model
,model
对象里拥有许多选项
(1) namespace
: 接收一个字符串表示model
的命名空间,同时也是他在全局 state
上的属性。
(2) state
: 接收一个对象表示页面状态初始值,优先级低于传给 dva()
的 opts.initialState
。
(3) reducers
: 接收一个对象定义同步操作,唯一可以修改 state
的地方,
形式为 (state, action) => newState
其中第一参数表示上一次的state
,
action
如下,其中 action.payload
可以获得传进来的参数。
最后返回一个新的state
。
(4) effects
: 接收一个对象定义异步操作
格式为 *(action, effects) => void
或 [*(action, effects) => void, { type }]
。其中*
代表是es6
的generator
函数。
其中effects
是一个对象有{put, call, select}
:
put
类似于dispatch
触发一个action
,
call
用于进行异常操作,例如发送请求,
select
从model
里选择数据,要在effects
函数中使用state
里的数据,必须使用select
。
(5) subscriptions
: 订阅数据源
相当于一个监听器,可以监听路由变化,鼠标,键盘变化,服务器连接变化,状态变化等,这样在其中就可以根据不同的变化做出相应的处理,在这个subsription
中的方法名是随意定的,每次变化都会一次去调用里面的所有方法,所以一边会加相应的判断
subscriptions:{
setup({
dispatch,history})
{
history.listen(({
pathname }) => {
// if (pathname === '/factoryInfo') {
// dispatch({ type: 'getList' })
// dispatch({ type: 'commonM/getOrgTree' })
// dispatch({ type: 'commonM/getDivisionTree' })
// }
});
}
}
3.在定义完model
之后,我们要使用 connect
来连接view
和model
。使用connect
时需要从'dva/connect'
导入。
**当在路由定义时,import
了modal
时,整个页面的组件都可以通过connect
来包装自己,**包装自己的含义就是将state
加到组件的props
里(在react
中,只要组件state
和props
才能驱动视图变化。
connect
接受一个函数作为参数,并且返回一个函数,返回的函数接受一个组件作为参数,并且返回连接了state
的包装后的组件。
export default connect(({
reportM, dataDetailM }) => ({
reportM, dataDetailM }))(WasteCollectReport);
mapStateToProps(xxx,xxx,xxx){
//建立state和props的对应关系,这里的参数是model的namespace
return {
someProps:xxx,
somePross:xxx}}
export default connect({
mapStateToProps,mapActionToProps})(C)
被包装后的组件C
的props
里包含了mapStateToProps
返回的字段。
4.dispatch(action)
用于触发action
,action
如上描述一个行为。其中的type
描述了要执行的函数。
在连接了model
的组件上,我们可以使用props
访问到dispatch
方法。这也是我们唯一在组件里调用reducers
和effects
的方式。
六,组件页面
1.使用路由跳转的组件props
包含了什么。
2.从上图可以看出我们可以在props
里访问到model
字段,也可以使用触发action
的方法dispatch
,以及路由跳转的相关参数。
六,loading
对象,
1,dva
框架内置了loading
插件,我们可以在全局中import
后使用。
import createLoading from 'dva-loading';
export const app = dva(createLoading());
这样在所有的组件中都可以使用loading
对象。
2,具体用法,用于异步操作,在异步操作开始时为true
,结束时为false
。
export default connect(
({
userAndlogin,
loading,
}) => ({
userAndlogin,
submitting: loading.effects['userAndlogin/login'],
}),
)(Login);