目录
前言
- 项目初始为umi脚手架进行初始化<初始化过程:http://t.csdn.cn/cuTaY>
- 工程中加载了umi自带的antd ui框架
- 此篇应用需要先掌握React+Redux的基本概念<Redux交互:http://t.csdn.cn/K59ec>
- 此篇主要讲解如何在umi工程中结合dva进行交互,数据更新,异步请求等操作
知识储备
需要先了解如下几个内容的基本使用:
generator函数,Dva基本结构<以下主要针对使用进行阐述,概念简短概括>
-
generator函数
1. generator函数为es6中暴露的解决异步编程的一种方式<可理解为可人为控制函数的执行,人为中断函数执行>
2. 该函数为了区别于普通函数,在function关键字后增加了 * 加以区分
3. 普通函数被调用会立马执行,直到遇见return结束;
而generator函数的调用会返回一个遍历器对象,通过(将调用结果赋值给某个变 量).next()的方式继续调用,遇到yield就会暂停(可返回yield 后的内容);
如果此时再次 执行next(),则会再次触发下次执行。
/** * 普通函数 <声明 - 调用> */ function fn(){ return 'string' } //调用 fn(); //'string' /** * generator函数 <声明 - 调用 - 执行<采用next执行>(多次)> * .next()的执行会返回{value:该值为yield后的内容,done:该值为布尔,为true时函数执行完毕,为false * 则标识函数仍有内容可继续调用} */ function* gen(){ yield 'A'; console.log('执行第二次yield'); yield 'B'; yield 'C'; return 'D'; } //调用 <此时函数内部不用执行任何内容,即使第一行增加console也不会输出> const _ge = gen(); //执行 ge.next();// {value: 'A', done: false} ge.next();// 执行第二次yield //{value: 'B', done: false} <执行两部分> ge.next();// {value: 'C', done: false} ge.next();// {value: 'D', done: true} <此时函数执行结束,所以在done返回true>
-
Dva初识
1. 需要先确保项目中有dva(cnpm install dva)
2. umi项目中需要配置开启dva(于.umirc.ts中增加dva:{}即可)
3. 约定式model(默认访问/src/model目录下的内容)
3. 与视图组件关联(React-Redux中的connect进行关联),如果对于connect的连接操作不是很清楚,可以前往(http://t.csdn.cn/quRJL),进行参阅,其中有较为详细且易懂的讲解
//src/models/exampleModel.js /* * 该文件为一个标准的model层 * 为了后续方便讲解,该model会完善为一个包含基础业务逻辑的model层 */ export default { //<唯一>标识model,后续在视图组件中会用到,加以区分多个model<model的命名空间> namespace:'exampleModel', //model中的数据变量,类似于vue中的data(){} state:{ count:0,//用于存储一个数量值 data:[],//存储异步获取的数据 }, //<同步action>,主要是用来修改state中的数据 reducers:{ /** * 用于更新state中的数据,通过dispatch进行触发(该函数为纯函数,仅支持进行state的更新) * @param {Object} state 上方定义的state数据 * @param {Object} payload 传递进来需要进行更新的数据 * @return {Object} 返回修改后的state数据 */ updateSate(state,{payload}){ return {...state,...payload} }, //用于单纯计算的reducer addReducer: (state, { payload }) => { return { count: payload + state.count } }, }, //<异步action>,主要用来发送异步请求 effects:{ /** * 用于异步的数据交互,方法可通过外部引入 * @param {Object} payload 传递进来的参数 * call: 用来发送promise请求 <yield call(request,payload)> * put:用来触发action<发送dispatch> <yield put({type:'xxx',payload:{}})> * select: 用来获取state的数据内容 <yield select(state=>state.data)> * all: 类似于Promise.all,批量请求 <yield all([]> */ * syncPromise({payload},{call,put,select}){ //requestMeR为外部导入的promise请求(位于src/services/exampleService.js目录下,下方会有代码标注) const {data} = yield call(requestMeR,payload) //将接口中返回的数据存储于state中 yield put({type:'updateSate',data}) //将刚才存储的数据,取出来验证是否存储成功 const d = yield select(state=>state.exampleModel.data) console.log(d); } }, //常规用于当前model所在的视图层加载,用于监听当前路径等一系列的操作 //或者执行一些页面默认加载就需要触发的动作 subscriptions:{ setup({dispatch,history,query}){ history.listen(({pathName})=>{ //...do something }) } } }
//src/services/exampleService.js //需要用到umi内置的request方法 import {request} from 'umi'; //获取列表数据 export const requestMeR = async (params) =>{ return request('/api/queryTableData',{ methods:'get', params }) }
实际交互
- 通过 函数式组件 && class组件 两种交互方式进行阐述
- 两种模式采用 一套model 交互,区别于调用交互方式
- 在进行实际的交互之前,需要先了解react,react-redux,antd的基本使用
-
函数式组件
//src/pages/exampleFunComponent.tsx //函数式组件进行model的连接 import {connect} from 'dva'; import {Button,Table} from 'antd'; //此处的常量为方便后续的统一dispatch动作的触发 const namespace = 'exampleModel'; const columns = [{title:'所属系统',dataIndex: 'sysName',key:'sysName'}, {title:'白名单类型',dataIndex: 'type',key:'type'}, {title:'白名单内容',dataIndex: 'content',key:'content'}] /** * 定义视图组件 * @param {Object} exampleModel 对应当前视图组件的model层的state数据对象集合 * @param {Function} mapHandlerReducer 【自定义名称】对应model中的reducer中的某个方法 * */ const ExampleFunComponent = (exampleModel:{count,data},mapHandlerReducer,handleUseEffect) => { const handleClick = () =>{ mapHandlerReducer(); } return ( <> <Button onClick={handleClick}>点击进行计算,每次增加 100</Button> <div>计算过后的数据:{count}</div> <Button onClick={()=>handleUseEffect()}>点击触发effects中的异步请求</Button> {/* 下方为获取到的异步接口中的数据 */} {promiseData && <Table dataSource={data} columns={columns} rowKey={row=>row.id} />} </> ) } /** * 用于映射models中的详细reducer方法 * return出去的对象中: * key:为自定义的事件名称,映射于当前组件中的实际使用事件内容 * value:为通过dispatch去出发model中的reducer或者effects中的方法 */ const mapDispatch = dispatch => { return { mapHandlerReducer:() => dispatch({type:`${namespace}/addReducer`,payload:100}), handleUseEffect:() => dispatch({type:`${namespace}/syncPromise`}), } } /** * connect参数详解: * ({exampleModel})=>({exampleModel}) 目的为将model中的内容映射于当前ui视图组件,其中形参为指定 * 的model的命名空间所对应的值 * mapDispatch 为绑定model中的reducer中的方法于当前视图 */ export default connect(({exampleModel})=>({exampleModel}),mapDispatch)(ExampleFunComponent )
-
class组件
//src/pages/ExampleClassComponent.tsx //class式组件进行model的连接 import { Button, Table } from 'antd'; import { connect } from 'dva'; import { Component } from 'react'; const nameSpace = 'exampleModel'; const columns = [ { title: '所属系统', dataIndex: 'sysName', key: 'sysName' }, { title: '白名单类型', dataIndex: 'type', key: 'type' }, { title: '白名单内容', dataIndex: 'content', key: 'content' }, ]; //也可以采用此方式进行视图层的绑定 @connect(({ exampleModel}) => ({ exampleModel})) class ExampleClassComponent extends Component{ constructor(props) { super(props); } render(){ const { dvaComponentModel: { count, data}, dispatch} = this.props; return( <> <Button onClick={() => { dispatch({ type: `${nameSpace}/addReducer`, payload: 100 }); }} > 点击每次增加 100 </Button> <div>计算过后的数据:{count}</div> <Button onClick={() => dispatch({ type: `${nameSpace}/syncPromise` })}> 点击触发effects中的异步请求 </Button> {promiseData && ( <Table dataSource={data} columns={columns} rowKey={(row) => row.id} /> )} </> ) } } export default ExampleClassComponent;