使用dva的一些体悟

7,744 阅读6分钟

dva是支付宝前端团队时常维护的一个开源项目,会维护,维护,维护!!它集成了redux , react-router , 可能还用到了TypeScript等等,看github上说是基于react的最佳实践,使用下来确实感觉挺不错的。组件我没有用antd而是自己写的。

构建项目

首先你需要安装node我想应该前端都会用吧,当然react你也必须会。如果不会react和前端基础那估计你要去补一补了咯

1. 安装dva-cli

npm install dva-cli -g

2. 初始化dva项目

dva new newDva
进入项目目录执行npm start 就可以看到你初始化的项目了

3. 文件目录

routes 和 models 两个文件夹是最重要的两个里面会有大量内容
utils 里面放的基本上是工具函数自己封装或者别的地方拿
services 里面基本是一些网络请求的api 在 models文件里面的 effects 内会用到
assets 里面会有一些静态的图片之类的

整个app 主要的逻辑加上组件都在src这个大的文件夹下面
mock 里面就是模拟的api接口

4. dva指令

1. npm start

启动项目,自动检测文件变化热更新页面。

2. npm build

打包项目。会在文件名后加上一个hash值并且压缩文件

3. dva g route example

创建一个路由,并且在router.js中自动注册这个路由。其实route目录下放的就是所有页面组件,他创建的就是一个页面。
会有两个文件,个人建议不用这个指令,手动创建文件夹作为一个页面,当前页面的所有组件放在这个文件夹里面,公共组件可以放在components文件夹下

import React from 'react';
import { connect } from 'dva';
import styles from './IndexPage.css';

function IndexPage() {
  return (
    ....
  );
}

IndexPage.propTypes = {
};

export default connect()(IndexPage);

这是初始化之后的首页组件模板,dva提倡状态组件。大致就是你无法在一个dva组件里面使用生命周期。
参数状态有对应的model去控制,函数类型组件直接返回html模板可能是一种对react的性能优化,当然你也可以在return中嵌套别的自定义组件。
return <OtherComponent />
一个顶级标签的规矩还是不能破坏的
在这里面css可以看到是以一个对象形式引入,其实是dva采用了css-model这种方式。具体的可以去看css-model。使用写法是这样:
<OtherComponent className={style.one} />
如果你要多个className 那你需要这样写
<OtherComponent className={style.one + " " + style.another} />

4. dva g model example

这个指令非常好用,他会创建一个example.js的文件作为一个模型,并且在router.js中自动注册这个模型。app.model(require('./models/example'));
这里的一个模型应该和route里面的文件夹一一对应起来,相当于平时使用的redux。里面有当前这个路由组件的state,具体是长这个样子的

export default {

  namespace: 'example',

  state: {},

  subscriptions: {
    setup({ dispatch, history }) {  // eslint-disable-line
    },
  },

  effects: {
    *fetch({ payload }, { call, put }) {  // eslint-disable-line
      yield put({ type: 'save' });
    },
  },

  reducers: {
    save(state, action) {
      return { ...state, ...action.payload };
    },
  },

};

namespace 是这个model的命名,他是一个全局的,只能出现一个,而且最好是和组件对应,

state是这个model里面的数据,也是他对应组件的state

dispatch 是触发方法的一个函数,在model里面使用可以使用

subscriptions:我认为相当于组件的所有生命周期都可以在这里找到对应的api去调用,常用是setup在组件渲染之前会触发,setup一般是直接出发effects里面的方法

> dispatch({ type: 'fetch'}); //如果是当前model可以直接写方法名
如果是别的model的那你需要前面加上model名字 { type: 'OtherModel/fetch'}

effects:所有网络请求都应该放在这里面,应为它使用了generator来处理异步,这里是唯一一个地方可以处理异步请求的。当然你要大牛可以自己在别的地方写咯。

  • 在fetch这个函数里面传入得第二个对象 { call, put },是定义好的api可以去看官方文档;
  • call方法里面可以传入一个方法,和一个参数,他会自动执行这个方法,一般我们就把网络请求放在这里面 const data = yield call( apiFunction ); 拿到请求回来的数据了;
  • 调用const data = yield put( { type : "save" , payload :{data} );调用当前组件的save方法存入当前的state,其实这里和subscriptions中的dispatch方法类似;
  • 那么其实所有model的state都是共享的你可以在其他model中拿到这个model的state,或是所有model的stateconst data = yield select( { modelName } => modelName.stateValue );
  • 组件间的跳转也应当在这里 import { routerRedux } from 'dva/router'; yield put( routerRedux.push("/targit"));

reducers:这里面放的全是改变state的函数传入两个参数,当前model的state和数据,在这里利用传入的数据对state进行修改。一般会在effects里面被调用,或者是在和这个模块绑定的组件里面通过事件回调,

dispatch({ type: 'save'})

在组件中使用model

通过函数参数方式传入
导出涌dva的connect方法连接组件和model;

const IndexPage = ({ dispatch, example })=> {
    return <Index />
}
export default connect(({ example }) => ({
   example
}))(IndexPage);

那么你在这个组件里面就可以拿到example这个model的所有state和dispatch这个方法
state:example.stateName获取这个model的一个state属性值
为了能在组件中触发model的方法做一系列的操作那么就需要使用dispatch了

在组件事件中触发

function(){
    dispatch({
        type : "model/name"
        payload : ""
    })
    }

触发了这个model的name方法做了一系列操作;

如果你的组件必须要用到生命周期

那你也可以用class 来声明一个组件
class AppointmentPage extends React.Component {
    handleClick(){
        this.props.dispatch({
            type: 'modelName/name'
        })
    }
    render(){
        return (...)
    }
}
export default connect(({ modelName }) => ({
 modelName
}))(Component);

dispatch方法会在this.props里面。

5.如何模拟后台接口返回数据

我采用了nodejs作为本地服务器
需要在.roadhogrc文件中添加

"proxy": {
    "/api": {
      "target": "http://127.0.0.1:3000/api/",
      "changeOrigin": true,
      "pathRewrite": { "^/api" : "" }
    }
  },

让他去代理你的后台服务那么你在请求的时候地址只需要写 “api/...” 推荐使用fetch。

总结

由于之前开源协议的原因可能会用很多大佬放弃react什么的啊,但是我觉得如果是做开源项目完全没必要,企业内部呢厉害的应该会自己封装类似的,大部分服务于国内的项目其实没什么必要换,Facebook根本进不来嘛,而且这样的思路值得学习。
dva的使用一开始可能会非常不适应,但是写过之后感觉还是非常nice的结构清晰,写法也不复杂,事件处理都封装的不错,特别是在redux这里的封装,使用起来非常舒服,如果自己写估计就不是这么一点复杂度了,命令行指令善用。dva用了较多的解构赋值箭头语法generator等等,不会的要多看es6。放一张图帮助理解


图是偷来的。。
如果有什么建议或者不对的可以讨论啊!!!