由於積分商城項目接觸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) 複製代碼