由于积分商城项目接触dva搭建的项目,因为和之前使用vue框架不一样,边完成需求,边学习框架,现对学习过程作一个记录,但愿对后来接触dva的小伙伴有所帮助,有什么错误的地方,你们一块儿纠正。javascript
dva 首先是一个基于 redux 和 redux-saga 的数据流方案,而后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,因此也能够理解为一个轻量级的应用框架。css
官方解释是这样,在我理解,dva是一个对react进行简单封装,更方便进行开发的react框架。html
dva也使用脚手架进行安装。vue
$ npm install dva-cli -g
复制代码
是否是很熟悉,和vue相似,用法也和vue-cli相似java
$ dva new dva-quickstart
复制代码
使用newnode
$ cd dva-quickstart
$ npm start
复制代码
本地就跑起来了react
在使用时咱们搭配antd开发,antd为react的ui框架,有了ui框架开发起来更加方便快捷webpack
$ npm install antd babel-plugin-import --save
复制代码
注意,若是node版本高于5.4.0会出现报错git
解决办法: 1.node降版本 2.删除node_modules文件夹web
我是node5.6.0,因此
$ npm install antd babel-plugin-import --save
$ npm install
复制代码
编辑 .webpackrc,使 babel-plugin-import 插件生效。
{
+ "extraBabelPlugins": [
+ ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
+ ]
}
复制代码
目录结构
|- mock
|- node_modules
|- package.json
|- public
|- src
|- asserts
|- components
|- models
|- routes
|- services
|- utils
|- router.js
|- index.js
|- index.css
|- .editorconfig
|- .eslintrc
|- .gitignore
|- .roadhogrc.mock.js
|- .webpackrc
复制代码
和vue-cli生成的目录结构相似,其中有几个不一样点强调一下
咱们经过vue对比进行开发,因此从咱们熟悉的开始(routes已换成pages)
// .webpackrc.js
import { resolve } from 'path'
let publicPath
module.exports = {
publicPath,
outputPath: './dist',
// 按需加载antd组件
extraBabelPlugins: [
[
'import',
{
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
},
],
],
alias: {
components: resolve(__dirname, './src/components'),
utils: resolve(__dirname, './src/utils'),
pages: resolve(__dirname, './src/pages'),
services: resolve(__dirname, './src/services'),
api: resolve(__dirname, './src/api'),
models: resolve(__dirname, './src/models'),
img: resolve(__dirname, './src/assets/img'),
},
}
复制代码
|- mock
|- node_modules
|- package.json
|- public
|- src
+ |- api
|- asserts
|- components
|- models
|- pages
|- services
|- utils
|- router.js
|- index.js
|- index.css
|- .editorconfig
|- .eslintrc
|- .gitignore
|- .roadhogrc.mock.js
|- .webpackrc
复制代码
例如:
// src/api/commodity.js
// 商品列表
export const commodityListUrl = url
复制代码
// src/services/commodityService.js
import request from 'utils/request'
import {
commodityListUrl,
} from 'api/commodity'
import { createAFordownLoad } from 'utils/methods'
/** * 获取商品列表 * * @param {*} payload * @returns */
export const getCommodityList = async payload => {
try {
const { result } = await request({
url: `${commodityListUrl}`,
data: payload,
})
return Promise.resolve(result)
} catch (e) {
return Promise.resolve(e.message)
}
}
复制代码
// src/router.js 注意这里是示意代码 不是业务代码,在实际开发中会根据状况变化
import React from 'react';
import { Router, Route } from 'dva/router';
import commodity from './pages/list';
// 伪装有其余
import example from './pages/example';
function RouterConfig({ history }) {
return (
<Router history={history}>
<Route path="/" exact component={commodity} />
<Route path="/example" exact component={example} />
</Router>
);
}
export default RouterConfig;
复制代码
dva 内置了 dynamic 方法用于实现组件的动态加载,用法以下:
import dynamic from 'dva/dynamic';
const UserPageComponent = dynamic({
app,
models: () => [
import('./models/users'),
],
component: () => import('./routes/UserPage'),
})
复制代码
实际使用时,能够对其进行简单的封装,不然每一个路由组件都这么写一遍很麻烦。 例如咱们能够:
import routes from '' // 把Route集中写进一个文件
function RouterConfig({ history }) {
return (
<Router history={history}> <Switch> {routes.map(({ path, ...dynamics }, key) => ( <Route key={key} path={path} exact component={dynamic({ app, ...dynamics })} /> ))} </Switch> </Router> ); } 复制代码
Model 是 dva 最重要的部分,能够理解为 redux、react-redux、redux-saga 的封装。 一般项目中一个模块对应一个 model,一个基本的 model 以下:
import { hashHistory } from 'dva/router'
import { query } from '../services/users'
export default {
namespace: 'commodity',
state: {
list: [],
},
subscriptions: {
setup({ dispatch, history }) {
// 进入页面就调用
history.listen(location => {
if (location.pathname === '/') {
dispatch({
type: 'query',
payload: {},
})
}
})
},
},
effects: {
*query({ payload }, { select, call, put }) {
yield put({ type: 'showLoading' })
const { data } = yield call(query)
if (data) {
yield put({
type: 'querySuccess',
payload: {
list: data.data,
total: data.page.total,
current: data.page.current,
},
})
}
},
*create() {},
// delete为关键字
*'delete'() {},
*update() {},
},
reducers: {
showLoading(state, action) {
return {
...state,
loading: true,
}
},
showModal() {},
hideModal() {},
querySuccess(state, action) {
return {
...state,
...action.payload,
loading: false,
}
},
createSuccess() {},
deleteSuccess() {},
updateSuccess() {},
},
}
复制代码
|- src
|- api
|- asserts
|- components
|- models
|- pages
+ |- commodity
+ |- component
+ |- dataTable.js
+ |- list.js
复制代码
// src/pages/commodity/component/dataTable.js
import React, { Component } from 'react'
import { Table, Button } from 'antd' // antd 组件
class DataTable extends Component {
render() {
const {
data: { list, pagination },
} = this.props // 获取数据
const columns = [] // 定义表头及内容
return (
<Table rowKey="draftSn" columns={columns} DataTable dataSource={list} pagination={pagination} /> ) } } export default DataTable 复制代码
// src/pages/commodity/list.js
import React, { Component } from 'react'
import { connect } from 'dva'
import DataTable from './component/dataTable' // 注意组件必定要大写
class CommodityList extends Component {
state = {
list: [],
}
render() {
// 从modal获取数据
const {
commodity, // modal数据
dispatch, // service方法
location, // 能够获取url相关信息
history, // 路由
} = this.props
// 为组将传参
const tableProps = {
data: commodity,
dispatch,
history,
}
return (
<div> <DataTable {...tableProps} /> </div> ) } } // 连通modal和页面数据 function mapStateToProps({ commodity }) { return { commodity } } export default connect(mapStateToProps)(CommodityList) 复制代码