zoukankan      html  css  js  c++  java
  • Dva框架从初识到上手

    引言

    最近工作需要用dva框架,同事帮我培训了一下,有一点点认识,在此总结。

    当然,以后对dva可能会了解更透彻,文章会不断更新的。

     

    初识

    开始看架构代码,没有看文档的时候,不知道里面的几个关键字是什么意思:

    1. Effect
    2. Reducer
    3. Dispatch
    4. mapStateToProps
    5. NAMESPACE

    一头雾水,感觉好复杂。听完同事讲解以后,觉得redux代码量好大。

    虽然公司其他项目用的不是这个框架,但是最近项目需要,没办法,学呗!

    关于dva

    dva 是基于现有应用架构 (redux + react-router + redux-saga 等)的一层轻量封装;

    数据流向: 数据的改变发生通常是通过:

    用户交互行为(用户点击按钮等)
    浏览器行为(如路由跳转等)触发的
    当此类行为会改变数据的时候可以通过 dispatch 发起一个 action ,如果是同步行为会直接通过Reducers 改变 State ,如果是异步行为(副作用)会先触发 Effects 然后流向 Reducers 最终改变State 。 所以在 dva 中,数据流向非常清晰简明,看最后思维导图。

    关于Redux-saga

    Redus-saga 是一个 redux 的中间件,主要用来简便而优雅的处理 redux 应用里的副作用(side effect相对于pure function这类概念而言的)。它之所以可以做到这一点主要是使用了ES6 里的一个语法: Generator 。使用 Generator 可以像写同步的代码一样编写异步代码,这样更加容易测试。(其实这里也不是特别懂,后面还要研究一下)

    现在回头看(虽然才过去两天),感觉走了弯路。因为项目时间比较紧,同事跟我讲完,我想都没想,就按照他跟我说的逻辑,复制粘贴(在原来代码基础上),然后哪里报错修哪里。

    后来越弄越搞不清楚。所以,拿到新东西,开始一定是看文档,看文档,看文档。

    后来我看文档,把不懂的再确认一遍,看一下之前别人是怎么写的,然后从头开始写自己的任务:

    1 添加路由(page)

    2 添加布局以及组件

    3 设计Model

    4 connect关联

    上手

    下面根据以上四个步骤,我们来看一个用例

    这个就是同事跟我讲解的时候写的,很清晰明了

    step1:routes

    这里没有写组件,如果有组件这里可以抽出来。

    关于多层级组件传数据,我目前还不是完全明白,等后面搞明白了加上。

    import React, { Component } from 'react'
    import { connect } from 'dva'
    import './index.less'
    import { NAMESPACE } from '../../models/evaluateManage/constants';
    import { Row , Col, Input, Button, Select } from 'antd'
    const Option = Select.Option
    
    const mapStateToProps = (state) => ({
        ...state[NAMESPACE],
        description: state[NAMESPACE].description,
        menuList: state[NAMESPACE].menuList,
    })
    
    const mapDispatchToProps = (dispatch) => ({
        dispatch,
        updateState(val, cb){
            dispatch({
                type:`${NAMESPACE}/updateState`,
                payload:{
                    params: val,
                    cb: cb
                }
            })
        },
        getMenu(val, cb){
            dispatch({
                type: `${NAMESPACE}/getMenu`,
                payload: {
                    params: val,
                    cb: cb
                }
            })
        }
    })
    
    @connect(mapStateToProps, mapDispatchToProps)
    class EvaluateManage extends Component{
    
        constructor(props){
            super(props)
            this.state = {
                inputMsg: undefined
            }
        }
        syncMethod = () => {
            const { inputMsg } = this.state
            this.props.updateState({
                description: inputMsg
            }, (res) => {
                debugger
            })
        }
        asyncMethod = () => {
            this.props.getMenu({
                tenantId: "_1RNSq2S"
            })
        }
        asyncMethod = () => {
            this.props.getMenu({
                tenantId: "_1RNSq2S"
            })
        }
        asyncMethodCallback = () => {
            this.props.getMenu({
                tenantId: "_1RNSq2S"
            },(res = []) => {
                this.props.updateState({
                    menuList: res,
                    description: "通过回调机制"
                })
            })
        }
    
        inputMethod = (e) => {
            let value = e.target.value
            if(!value){
                value = "我是描述"
            }
            this.setState({
                inputMsg: value
            })
        }
    
    
        render(){
            const { inputMsg } = this.state
            const { menuList = [] } = this.props
            return <div styleName="rule-wrapper">
                <h1 styleName="ruleTitle">{this.props.description}</h1>
                <h1 styleName="ruleTitle">我是输入内容:{inputMsg}</h1>
                <Row>
                    <Col span={24}>
                        <Input onChange={this.inputMethod} value={inputMsg}/>
                    </Col>
                </Row>
                <Row>
                    <Col span={8}>
                        <Button size="large" onClick={this.syncMethod}>我是同步按扭</Button>
                    </Col>
                    <Col span={8}>
                        <Button size="large"  onClick={this.asyncMethod}>我是异步按扭</Button>
                    </Col>
                    <Col span={8}>
                        <Button size="large"  onClick={this.asyncMethodCallback}>我是异步按扭回调机制</Button>
                    </Col>
                </Row>
                <ul>
                    {
                        menuList.map((item) => {
                            const { name, code} = item
                            return <li>{name}   {code}</li>
                        })
                    }
                </ul>
                
                
            </div>
        }
    }
    
    export default EvaluateManage
    

      inistate

    const evaluateManage = {
        "description": "我是描述",
        "menuList": []
    }
    

      model

    import * as constants from './constants'
    import {initState} from "../initState";
    import {apiCallTemplate} from 'Apis/api'
    
    
    export const getMenu = apiCallTemplate('getMenu', constants.NAMESPACE)
    
    
    export default {
        namespace: constants.NAMESPACE,
        state: initState[constants.NAMESPACE],
        reducers: {
            updateState(state, { payload }){
                const { params, cb } = payload
                cb && cb()
                return {
                    ...state,
                    ...params
                }
            } 
        },
        effects: {
            *getMenu({ payload: {params = {},cb } }, { call, put}){
                const { data } = yield call(getMenu, params)
                const { menuList = [] } = data
                if(cb){
                    cb(menuList)
                }else{
                    yield put({
                        type: 'updateState',
                        payload: {
                            params: {
                                menuList,
                                description: "通过非回调机制"
                            }
                        }
                    })
                }
                
            }
        },
        subscriptions: {},
    }
    

     最终效果见下图

      点击同步按钮

       点击异步按钮,这里调了getMenu接口

     

     异步和异步回调效果差不多的,后者多了回调

    dva思维导图

     dva框架思维导图

    写在最后

    model中的reducers跟effects是负责修改状态state的方法,其中reducers是同步方法,effects是异步方法,reducers跟effects中的方法

    组件中修改状态需要通过在Action中调用dispatch方法来调用reduces或effects中的方法来实现,

    因此需要在组件中定义Action方法,页面根组件中的mapDispatchToProps里面负责定义Action,

    所以在页面根组件中需要在mapDispatchToProps中定义操作reducers或effects的方法(action)

     

    dva将所有与数据操作相关的逻辑集中放在一个地方处理和维护,在数据跟业务状态交互比较紧密的场景下,会使我们的代码更加清晰可控。

    对于一个大型管理系统,由于要进行大量的数据操作,在设计model时将不同类型的业务需求数据操作分开处理,便于维护。

    项目的开发流程一般是从设计 model state 开始进行抽象数据,完成 component 后,将组件和model 建立关联,通过 dispatch 一个 action ,在 reducer 中更新数据完成数据同步处理;

    当需要从服务器获取数据时,通过 Effects 数据异步处理,然后调用 Reducer 更新全局 state 。

    以上一个单向的数据流动过程。

    解决了 redux 中代码分散和重写问题。

    总之,Dva:Build redux application easier and better。

    这里代码量确实比mobx的大,但这套框架也确实有可取之处。

    阿里云主要用的语言是React,架构: Redux,框架:dva

    备注:

    react高阶组件学习

    前端react迭代方向,尽量少用高阶组件,后期不好维护。多将组件细分,组件越小越好,类似乐高积木一样。

    不过高阶组件还是要会运用。

  • 相关阅读:
    高可用网站多点部署架构实战经验总结
    使用阿里云发送邮件完美解决 端口 25 465
    阿里云 SSL 证书 总结
    支付宝支付接入流程
    阿里云服务器ECS的环境部署和安装
    对接 第三方物流APP 手机版
    智付支付接入心得
    二次开发本地配置域名
    从1到n整数中1出现的次数:O(logn)算法
    MongoDB——增删改查
  • 原文地址:https://www.cnblogs.com/rong88/p/11664496.html
Copyright © 2011-2022 走看看