Dva.js

Amos Xu

Amos Xu

Front End Engineer|前端开发

什么是Dva.js?

  • 一个处理数据流程的框架。
  • 基于redux以及redux-saga
  • 额外配置react-router以及fetch
  • https://dvajs.com/

快速开始

$ npm install dva-cli -g
$ dva -v
$ dva new "project name" // 新建dva项目
$ cd "project name"
$ npm start //启动后可访问8000端口

项目入口&创建dva()实例

scr/index.js中会创建dva()实例

import dva from 'dva';
import './index.css';
// 1. Initialize
const app = dva();
// 2. Plugins
// app.use({});
// 3. Model
// app.model(require('./models/example').default);
app.model(require('./models/users').default)
// 4. Router
app.router(require('./router').default);
// 5. Start
app.start('#root');

每一步的概念都在注释中非常简洁明了,最后会被挂载到index.html下id为root的元素上

export interface DvaInstance {
/**
* Register an object of hooks on the application.
*
* @param hooks
*/
use: (hooks: Hooks) => void,
/**
* Register a model.
*
* @param model
*/
model: (model: Model) => void,
/**
* Unregister a model.
*
* @param namespace
*/
unmodel: (namespace: string) => void,
/**
* Config router. Takes a function with arguments { history, dispatch },
* and expects router config. It use the same api as react-router,
* return jsx elements or JavaScript Object for dynamic routing.
*
* @param router
*/
router: (router: Router) => void,
/**
* Start the application. Selector is optional. If no selector
* arguments, it will return a function that return JSX elements.
*
* @param selector
*/
start: (selector?: HTMLElement | string) => any,
}
export default function dva(opts?: DvaOption): DvaInstance;

以上为暴露出的dva实例的定义

核心概念 Model

对于dva.js 而言其核心就是让model模型成为一个可以包含同步state的reducers,异步请求逻辑的effects以及数据的订阅subscriptions.

export interface Model { // 这是源码中对于Model的接口定义(Typescript)
namespace: string,
state?: any,
reducers?: ReducersMapObject | ReducersMapObjectWithEnhancer,
effects?: EffectsMapObject,
subscriptions?: SubscriptionsMapObject,
}

由以上源码可知对于模型model而言,其对应的namespace是必不可缺的,而对于state,reducers等来说是可以选择性定义。

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 };
},
},
};

example-model

其中

state为状态(数据)

reducers是同步处理的任务,如删除等

effects为异步操作,其语法来自Generator,可进行异步网络请求。

subscriptions 是一种订阅操作,可以订阅如路由跳转操作。作用类似于拦截器。如下代码就是当路由跳转到/users的时候dispatch一个effects里的fetch异步操作用来加载进入当前路由页面时候的数据。

subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname, query }) => {
if (pathname === '/users') {
dispatch({ type: 'fetch', payload: query });
}
});
},
},

模型model需要在src/index.js中去进行注册

app.model(require('./models/example').default);
// 至于后面为什么要.default 可以在代码中直接console.log出require('./models/example') 查看打印出的对象,其中会看到一个default

connect 链接

在完成了model的定义之后,在页面中,需要使用connect方法链接model和component

// export default;
export default connect(({ xxx }) => ({
xxx,
}))(Xxx);

此时 在创建组件函数的时候接收即可完成数据的传入