Umi+Dva初印象<基础应用,结构,流转逻辑>

2023-11-19

目录

前言

知识储备

generator函数        

Dva初识

实际交互

函数式组件

class组件


前言

  • 项目初始为umi脚手架进行初始化<初始化过程http://t.csdn.cn/cuTaY>
  • 工程中加载了umi自带的antd ui框架
  • 此篇应用需要先掌握React+Redux的基本概念<Redux交互http://t.csdn.cn/K59ec>
  • 此篇主要讲解如何在umi工程中结合dva进行交互,数据更新,异步请求等操作

知识储备

需要先了解如下几个内容的基本使用:

generator函数,Dva基本结构<以下主要针对使用进行阐述,概念简短概括>

  1. 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>
    
  2. 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
        })
    }

实际交互

  1. 通过 函数式组件 && class组件 两种交互方式进行阐述
  2. 两种模式采用 一套model 交互,区别于调用交互方式
  3. 在进行实际的交互之前,需要先了解react,react-redux,antd的基本使用
  1. 函数式组件

    //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 )

  2. 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;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Umi+Dva初印象<基础应用,结构,流转逻辑> 的相关文章