Dva学习笔记小册

安装 dva-cli

$ npm install dva-cli -g
$ dva -v
dva-cli version 0.9.1

创建项目

dva new dva-quickstart//dva-quickstart == 项目名字

使用 antd

npm install antd babel-plugin-import --save

编辑 .webpackrc,使 babel-plugin-import 插件生效。

{
+  "extraBabelPlugins": [
+    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
+  ]
}

路由

在项目的src文件下 dva会自己创建一个router.js文件,即当前项目的路由配置。不需要自己过多配置,引入组件以及规定好path即可

路由跳转

import { Link,withRouter,routerRedux } from 'dva/router'

class Product extends React.Component {
      goHomeRedux = (e)=>{
        //这个也可以不用传递hittory来进行跳转
        this.props.dispatch(routerRedux.push('./'))
    }
      goHome = (e)=> {
        //如果当前组件没有被路由组件包裹 那么必须要由被包裹的父组件把history方法通过props的方式传递下来
        this.props.history.push('./')
    }
  render(){
    return (
        <Link to="./">去首页</Link>
                <Button type="dashed" onClick={ this.goHome }>去首页2</Button>
                <Button type="dashed" onClick={ this.goHomeRedux }>去首页3</Button>
    )
  }
}
//withRouter 高阶函数可以让组件不用传递history也可以使用路由操作
export default withRouter(Product)

model

dva 通过 model 的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers,处理异步逻辑的 effects,订阅数据源的 subscriptions 。

//这个是dva自带封装好的request请求方式
import * as api from '../services/example'
export default {
    namespace:'product',//定义命名空间 用于识别分开的模块 表示在全局 state 上的 key
    state :{//初始化状态数据
        productList : [
            {
                id:1,
                name:'kkk'
            },
            {
                id:2,
                name:'air'
            }
        ]
    },
    reducers:{//等同于 redux 里的 reducer,接收 action,同步更新 state
        //这里会做数据覆盖并更新的操作
        updateList(state,action){
            //state就是状态 action是参数
            let currentProductList = deepClone(state)
            currentProductList.productList.push(action.payload)
            return currentProductList
        }
    },
    effects:{
        //generator语法糖
        *updateListAsync ({ payload },{call,put} ){
            yield put({
                type:'updateList',
                payload
            })
        },
      //异步操作处理
        *updateHttp({ payload },{call,put} ){
            //payload 就是每次掉用这个方法传递的参数
          /*
          比如这里payload拿到的就是{id:1001}
            clickProductListHTTP = ()=>{
        this.props.dispatch({
            type:'product/updateHttp',
            payload:{
                id:1001
            }
        })
    }
          */
            console.log(payload,'payload-updateHttp')
            //网络请求
            const result = yield call(api.getProduct,payload)
            const data = result.data
            console.log(data,'data-updateHttp')
            if(data){
                yield put({
                    type:'updateList',
                    payload:data
                })
            }
        }
    },
    subscriptions: {
        //这个函数叫什么名字都可以
        setup({ dispatch, history }) {  // eslint-disable-line
            /*
                dispatch 掉用reducers中定义的事件
                history 就是路由值 
                {
                    hash: ""
                    pathname: "/ProductPage"
                    search: ""
                    state: undefined
                }
            */
            const curObj = {
                name:'curObj',
                id:6
            }
            dispatch({
                type:'updateList',
                payload:curObj
            })
            console.log(dispatch,'dispatch-setup')
        },
        // hello({ dispatch, history }){
        //     console.log(dispatch,'dispatch-hello')
        // },
        setupHistory({ dispatch, history }){
            history.listen((location)=>{
                console.log(location,'location')
            })
        },
    },
}

function deepClone (arr){
    console.log(arr,'arr---')
    //分开写是因为写一起会报错
    const _obj = JSON.stringify(arr),
        cloneObj = JSON.parse(_obj)
    return cloneObj
}

在定义这个模块之后 必须要在最外层的index.js引入

import dva from 'dva';
const app = dva();

// 3. Model  在这里引用model default理由同router
app.model(require('./models/product').default);

//另外一种方式就是统一引入 不是单独文件一个一个引入
/*
    这种统一引入的方式首先要在model定义一个总的管理全部model的js
    //合并model
const context = require.context('./',false,/\.js$/);
export default context
    .keys()
    .filter(item=>item!=='./index.js')
    .map(key=>context(key))
    最后导出在最外层index.js进行引用
*/
require('./models').default.forEach(key=>app.model(key.default));

在组件中使用model

import React from 'react'
import Pcompenent from '../../components/Product'
import { connect } from 'dva'


class IndexPage extends React.Component {

    render(){
        // /dispatch为操作model定义的方法
        const { productList,dispatch,history } = this.props

        return (
            <div>
                IndexPage
                <Pcompenent productList={ productList } dispatch={dispatch} history={history}/>
            </div>
        )
    }
}
/*
    mapStateToProps是一个函数,用于建立组件跟 store 的 state 的映射关系
    传入mapStateToProps之后,会订阅store的状态改变,在每次 store 的 state 发生变化的时候,都会被调用
ownProps代表组件本身的props,如果写了第二个参数ownProps,那么当prop发生变化的时候,mapStateToProps也会被调用。
例如,当 props接收到来自父组件一个小小的改动,那么你所使用的 ownProps 参数,mapStateToProps 都会被重新计算)。
mapStateToProps可以不传,如果不传,组件不会监听store的变化,也就是说Store的更新不会引起UI的更新
*/
const mapStateToProps = (state, ownProps) => {
    return {
        //product这里是找到自己命名的命名空间
        productList:state.product
    }
}
//高阶函数进行连接
export default connect(mapStateToProps)(IndexPage);

内置mock数据

dva自带mock文件 要设置mock数据可以直接在这个文件夹下创建js文件

//在这里定义接口的方法 地址 以及返回参数
module.exports = {
    "GET /api/product" : {"name":"请求的数据",id:5}
}

然后还需要在.roadhogrc.mock.js这个文件进行读取文件的配置

// export default {
//     //引入mock地址
//     ...require('./mock/product')
// };


import fs from 'fs';
import path from 'path';
const mock = {}
fs.readdirSync(path. join(__dirname + '/mock' )). forEach(function (file) {
    if (file.match(/\.js$/)){
        Object.assign(mock, require('./mock/' + file))
    }
})
export default mock

这里一般配置api接口在services这个文件里进行配置

import request from '../utils/request';

export function query() {
  return request('/api/users');
}

export function getProduct(){
  return request('/api/product');
}

最后在某个组件内部进行请求

import * as api from '../services/example'

getHTTP = async ()=>{
  let data = await api.getProduct()
  console.log(data)
}

总结一下,个人感觉dva就是一个套react且轻量化的框架,内部东西很齐全,不需要过多自己从新开始搭建,内置的mock模块也很方便前后端分离进行开发,对前端自己造数据还是很友好了。model模块也很方便进行全局的状态管理个人感觉跟redux差不多便于上手,使用起来如果习惯了还是很舒服。但是requert这个感觉稍微有点鸡肋,自带的fetch配置如果遇到复杂点的项目,还是得自己重新把配置覆盖再写一遍。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容