Dva入门

# Dva 入门
概念:dva是体验技术部开发的react应用框架,将react-router/redux/redux-saga(异步操作)三个工具库包装在一起,简化API,让react应用更加方便、快捷。
dva是framwork,不是library,类似emberjs,使用依赖库本身的语法。简化开发,相当于一个大的语法糖。
数据流图:start-(connect)->view-(dispatch)->action
state:通过创建一个state对象,保存整个应用状态,
action:是一个对象,用来描述事件;
connect方法:一个函数,绑定state到view;返回的也是react组件,成为容器组件,是原始的UI组件的容器在外面包裹一层state。接收两个参数mapStateToProps函数,mapStateToProps函数返回一个对象,用于建立state到props的映射关系。
dispatch方法:一个函数,发送action到state;被connect的component会自动在props中拥有dispatch方法。




Provider和connect()非常优雅的将全局store提供给了每一个组件。让每一个组件可以非常方便的去使用全局的数据。
roadhog(如同webpack)
1. Model对象的属性
namespace:当前Model的名称。整个应用的state,由多个晓得Model的state以namespace为key合成。
state:该Model当前的状态,数据保存在这里,直接决定了试图层的输出。
reducer:Action处理器,处理同步动作,用来算出最新的state;
effects:Action处理器,处理异步动作;基于redux-saga实现,典型的就是I/O操作、数据库读写。不能直接修改state,由action触发。
Generator函数:effect是一个Generator函数,内部使用yield关键字,表示每一步的操作(不管是异步还是同步)
call和put:dva提供多个effect函数内部的处理函数,常用的是call和put. call是执行异步操作,put发出一个action,类似dispatch.
```
{
namespace: 'count',
state: 0,
reducers: {
add(state) { return state + 1 },
},
effects: {
*addAfter1Second(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'add' });
},
},
}
```
2. dva安装
一、开始新项目的准备工作:
1、安装dva-cli并确保版本在0.9.1或以上版本:
npm install dva-cli -g
检测版本号: dva -v



2、创建项目名为‘wmz’的新项目:
dva new wmz
3、安装antd 和 babel-plugin-import ,babel-plugin-import 是用来按需加载 antd 的脚本和样式的,需要用tnpm 去下载ant插件。
 
下载tnpm:有的不需要也可以
npm install tnpm -g --registry=http://registry.npm.alibaba-inc.com
tnpm install
下载antd:
npm install antd babel-plugin-import --save
注意:下载完插件后,需要在.webpackrc文件中添加以下内容,才能使 babel-plugin-import 插件生效。
"extraBabelPlugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
]
4、准备工作做完之后,开始启动项目:
npm start
二、新项目实战
1、创建路由,路由可以想象成是组成应用的不同页面。文件的位置:routes文件夹里面。
2、添加路由信息到路由表,在router.js中进行编辑,先引入路由文件,再设置文件路径.
此时,就已经可以在http:127.0.0.1:8000,看到页面信息了;
3、编写UI Component,文件位置:component文件夹里;场景:在多个页面分享UI元素(或者在一个页面使用多次),在dva里可以把这部分抽成component。
4、定义model,dva通过model的概念把一个领域的模型管理起来,包含同步更新state的reducer,处理异步逻辑的effects,订阅数据源的subscriptions。文件的位置在models文件夹里。
 
在这个model里:
namespace:表示在全局state上的key;
state: 是初始值;
reducer: 等同于redux里的reducer,接收action,同步更新state;
最后记得一定要在index.js文件里载入model:
 
app.model(require(‘./models/文件名’).default);
5、connect方法:把model和component串联起来。文件位置:routers文件夹里。
6、最后需要在index.js 中添加初始数据让项目run起来;
const app = dva();
三、项目模块安排
项目的整体设计模式:
1. 先设计model
namespace 是 model state 在全局 state 所用的 key,state 是默认数据。
异步处理:dva 通过对 model 增加 effects 属性来处理 side effect(异步任务),call,put;
键盘订阅事件:subscription和model绑定,用于订阅一个数据源,然后根据dispatch需要的action,数据源可以是当前时间、服务器的websocket、keyword输入、geolocation变化、history路由变化等。
2. 再设计component
通过 props 传入两个值,count 和 dispatch,count 对应 model 上的 state,在后面 connect 的时候绑定,dispatch用于分发 action
更新state是通过reducer处理的,也是唯一可以更新state的地方。
3. 最后链接model和component
router:写组件,接收dispatch和products两个参数;
小案例:
import React from 'react';
import {connect} from 'dva';
import ProductList from '../components/ProductList';

const Products = ({dispatch,products}) => {
function handleDelete(id){
dispatch({//调用dva中的方法
type:'products/delete',
payload: id,
})
};
return(
<div>
<h2>list of products</h2>
{/*给组件绑定两个时间,删除事件和同步处理数据dva */}
<ProductList onDelete={handleDelete} products={products}/>
</div>
 
)
}
 
export default connect(({ products})=>({
products,
}))(Products);
```
models:定义model,对state进行管理,处理组件中的同步的方法;
```
//在组件中调用
export default {
namespace : 'products',
state : [],
reducers : {
'delete'(state,{payload:id}){//接收两个参数state和delete接收的参数
return state.filter(item =>item.id !== id);//filter返回true或者false,是否保留该数据。
}
}

}
```
components:一个对象,接收父组件绑定在子组件上的方法和models;
```
import React from 'react';
import PropTypes from 'prop-types';//设置数据类型
import {Table,Popconfirm,Button} from 'antd';

const ProductList = ({onDelete,products}) =>{//接收方法
const columns = [{
title:'Name',
dataIndex:'name'
},{
title:'Actions',
render:(text,record)=>{ //编辑单元格
return(
//气泡框 onConfirm确认的
<Popconfirm title="删除?" onConfirm={()=>onDelete(record.id)}>
<Button>Delete</Button>
</Popconfirm>
);
}
}];
return(
<Table //表格
dataSource = {products}
columns = {columns}
/>
)
}
export default ProductList;
## Dva源码解析
1. roadhog 起的是 webpack 自动打包和热更替的作用。
2. dva是一个杉树,返回一个app对象;目前 dva 的源码核心部分包含两部分,dva 和 dva-core。前者用高阶组件 React-redux 实现了 view 层,后者是用 redux-saga 解决了 model 层。
3. src/index.js
在这里,dva 做了三件比较重要的事情:
使用 call 给 dva-core 实例化的 app(这个时候还只有数据层) 的 start 方法增加了一些新功能(或者说,通过代理模式给 model 层增加了 view 层)。
使用 react-redux 完成了 react 到 redux 的连接。
添加了 redux 的中间件 react-redux-router,强化了 history 对象的功能。
4. provider本质上是一个高阶组件,也是一种代理模式,接收 redux 生成的 store 做参数后,通过上下文 context 将 store 传递进被代理组件。在保留原组件的功能不变的同时,增加了 store 的 dispatch 等方法。
5. connect 也是一个代理模式实现的高阶组件,为被代理的组件实现了从 context 中获得 store 的方法。
6. initialState 是 state 的初始数据,优先级高于 model 中的 state,默认为 {}。
7. createLoading() 加载状态,在app.use(CreateLoading());根据state.loading.global指示全局loading状态。如果在组件中直接使用this.props.locading
## Dva
1. 解决的主要问题

简化了react-redux的部署文件的复杂度,能够快速上手;
2. 主要接口:
(1)后端接口:
配置路由,在点击按钮后,在componentWillMount中通过this.props.dispatch派发,在model中执行effects、reducer等操作;在servers的文件夹下发送网络请求需要通过request.js文件,后台接收:
export function patch(id, values) {
return request(`/api/users/${id}`, {
method: 'PATCH',
body: JSON.stringify(values),
});
}

(2)mock数据:在.roadhogrc.mock.js中添加配置
export default {
'GET /api/users': { users: [{ username: 'admin' }] },
}
export default {
'POST /api/users': (req, res) => { res.end('OK'); },
}
在roadhogrc中进行配置proxy;若是get请求,则可以直接在url后面进行拼接;

3. 主要执行路径

用户操作后或者路由跳转->dispatch(action),同步直接通过reducer更改state,异步先触发effects,然后通过reducer最终改变state.

4. 可配置及修改的类、函数和文件

(1)路由:通过浏览器的History API可以监听浏览器url的变化,从而控制路由相关操作
(2)在入口文件index.js中 可配置plugin/model/router
state:model的状态数据,对象形式;
action:是一个javascript对象,改变state的唯一途径。必须带有type属性,需要注意的是 dispatch 是在组件 connect Models以后,通过 props 传入的;
dispatch:payload是需要传递的信息;通过props传入的dispatch函数;
reducers:{ save(state,{payload: }){ return { }}}返回一个新值;
effects:{fetch({payload},{call,put})} 不能直接修改state,由action触发。call是执行异步操作, put发出一个action,类似dispatch.

import * as 自定义名 from '../services/service';

effects: {

*供组件调用的方法名({ payload: { 参数 }}, { call, put }) {

const result = yield call(自定义名.service中的方法名, 参数);//如果使用 {参数} ,则是一个对象

//把请求的数据保存起来
//数据更新会带动页面重新渲染
yield put({
type: 'save', //reducers中的方法名
payload:{
data: result.data //网络返回的要保留的数据
}
})
}
},
监听路由变化,当进入 /user 页面时,执行 effects 中的 fetch,以从服务端获取用户列表,然后 fetch 中触发 reducers 中的 save 将从服务端获取到的数据保存到 state 中。
effects: {
*fetch(action, { put, call }) {
const users = yield put(fetchUsers, action.data);
yield put({ type: 'save', data: users });
},
},
*create({ payload: values }, { call, put }) {
yield call(usersService.create, values);
yield put({ type: 'reload' });
},
*reload(action, { put, select }) {
const page = yield select(state => state.users.page);
yield put({ type: 'fetch', payload: { page } });
},
Subscription :语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是 当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。
(3)在.webpackrc中通过添加字段来进行自定义antd主题;
CSS Modules配置,

猜你喜欢

转载自www.cnblogs.com/naniandongzhi/p/9257399.html
dva