來源:https://pengtikui.cn/dva.js-get-started/css
——------------------------------------------------------------------------------------前端
dva.js 是一個基於 redux、redux-saga 和 react-router 的輕量級前端框架。node
本文寫的有點凌亂…react
安裝 dva-cli 用於初始化項目:webpack
1
2
3
|
npm install -g dva-cli
# 或
yarn global add dva-cli
|
建立項目目錄,並進入該目錄:git
1
2
|
mkdir your-project
cd your-project
|
初始化項目:github
1
|
dva init
|
而後運行 npm start
或 yarn start
便可運行項目。web
項目初始化之後,默認的目錄結構以下:npm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
|- 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
|
先安裝 antd
和 babel-plugin-import
:json
1
2
3
|
npm install antd babel-plugin-import --save
# 或
yarn add antd babel-plugin-import
|
babel-plugin-import
也能夠經過 -D
參數安裝到 devDependencies
中,它用於實現按需加載。
而後在 .webpackrc
中添加以下配置:
1
2
3
4
5
6
7
8
9
|
{
"extraBabelPlugins": [
[
"import", {
"libraryName": "antd",
"libraryDirectory": "es",
"style": true
}]
]
}
|
如今就能夠按需引入 antd 的組件了,如 import { Button } from 'antd'
,Button 組件的樣式文件也會自動幫你引入。
更多 .webpackrc
的配置請參考 roadhog 配置。
能夠在 .webpackrc
中添加 theme
字段直接進行主題自定義,可是若是自定義的變量太多,建議將其單獨提取取來方便管理。
建議在 ./src
目錄下新建名爲 theme.js
的文件,而後在 .webpackrc
中引入,以下:
1
2
3
|
{
"theme": "./src/theme.js"
}
|
theme.js
示例以下:
1
2
3
|
export default {
"primary-color": "#000",
}
|
更多可自定義的 antd 變量請參考 default.less。
使用 dva-cli 初始化的項目默認已經啓用了 CSS Modules,若是不想使用 CSS Modules,在 .webpackrc
中添加如下配置項便可禁用:
1
2
3
|
{
"disableCSSModules": true
}
|
如需開發過程當中代理 API 接口,在 .webpackrc
中添加以下配置便可:
1
2
3
4
5
6
7
8
|
{
"proxy": {
"/api": {
"target": "http://your-api-server",
"changeOrigin": true
}
}
}
|
如需 mock 功能,在 .roadhogrc.mock.js
中添加配置便可,如:
1
2
3
|
export default {
'GET /api/users': { users: [{ username: 'admin' }] },
}
|
如上配置,當請求 /api/users
時會返回 JSON 格式的數據。
同時也支持自定義函數,以下:
1
2
3
|
export default {
'POST /api/users': (req, res) => { res.end('OK'); },
}
|
具體的 API 請參考 Express.js@4。
當 mock 數據太多時,能夠拆分後放到 ./mock
文件夾中,而後在 .roadhogrc.mock.js
中引入。
HMR,即模塊熱替換,在修改代碼後不須要刷新整個頁面,方便開發時的調試。能夠在 .webpackrc
中添加以下配置以使用 HMR:
1
2
3
4
5
6
7
8
9
|
{
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr"
]
}
}
}
|
若是無效,請嘗試更新一下 babel-plugin-dva-hmr
。
env
字段是針對特定環境進行配置,由於 HMR 只在開發環境下使用,因此將配置添加到 development
字段便可,運行 npm run build
時的環境變量爲 production
。
dva 內置了 dynamic
方法用於實現組件的動態加載,用法以下:
1
2
3
4
5
6
7
8
9
|
import dynamic from 'dva/dynamic';
const UserPageComponent = dynamic({
app,
models:
() => [
import('./models/users'),
],
component:
() => import('./routes/UserPage'),
});
|
實際使用時,能夠對其進行簡單的封裝,不然每一個路由組件都這麼寫一遍很麻煩。
dva-loading 是一個用於處理 loading 狀態的 dva 插件,基於 dva 的管理 effects 執行的 hook 實現,它會在 state 中添加一個 loading
字段(該字段可自定義),自動幫你處理網絡請求的狀態,不須要本身再去寫 showLoading
和 hideLoading
方法。
在 ./src/index.js
中引入使用便可:
1
2
3
|
import createLoading from 'dva-loading';
const app = dva();
app.use(createLoading(opts));
|
opts
僅有一個 namespace
字段,默認爲 loading
。
Model 是 dva 最重要的部分,能夠理解爲 redux、react-redux、redux-saga 的封裝。
一般項目中一個模塊對應一個 model,一個基本的 model 以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import { fetchUsers } from '../services/user';
export default {
namespace:
'user',
state: {
list: [],
},
reducers: {
save(state, action) {
return {
...state,
list: action.data,
};
},
},
effects: {
*fetch(action, { put, call }) {
const users = yield put(fetchUsers, action.data);
yield put({ type: 'save', data: users });
},
},
subscriptions: {
setup({ dispatch, history }) {
return history.listen(({ pathname }) => {
if (pathname === '/user') {
dispatch({
type: 'fetch' });
}
});
},
},
}
|
namespace
是該 model 的命名空間,同時也是全局 state
上的一個屬性,只能是字符串,不支持使用 .
建立多層命名空間。
state
是狀態的初始值。
reducer
相似於 redux 中的 reducer,它是一個純函數,用於處理同步操做,是惟一能夠修改 state
的地方,由 action
觸發,它有 state
和 action
兩個參數。
effects
用於處理異步操做,不能直接修改 state
,由 action
觸發,也可觸發 action
。它只能是 generator
函數,而且有 action
和 effects
兩個參數。第二個參數 effects
包含 put
、call
和 select
三個字段,put
用於觸發 action
,call
用於調用異步處理邏輯,select
用於從 state
中獲取數據。
subscriptions
用於訂閱某些數據源,並根據狀況 dispatch 某些 action,格式爲 ({ dispatch, history }, done) => unlistenFunction
。
如上的一個 model,監聽路由變化,當進入 /user
頁面時,執行 effects
中的 fetch
,以從服務端獲取用戶列表,而後 fetch
中觸發 reducers
中的 save
將從服務端獲取到的數據保存到 state
中。
注意,在 model 中觸發這個 model 中的 action
時不須要寫命名空間,好比在 fetch
中觸發 save
時是 { type: 'save' }
。而在組件中觸發 action
時就須要帶上命名空間了,好比在某個組件中觸發 fetch
時,應該是 { type: 'user/fetch' }
。
在 ./src/index.js
中能夠看到以下代碼:
1
2
|
import dva from 'dva';
const app = dva();
|
app 就是 dva 實例,建立實例時 dva 方法能夠傳入一些參數,以下:
history 是給路由用的,默認爲 hashHistory
,若是想要使用 browserHistory,須要安裝 history
,而後在 ./src/index.js
引入使用:
1
2
3
4
5
|
import dva from 'dva';
import createHistory from 'history/createBrowserHistory';
const app = dva({
history: createHistory(),
});
|
initialState 是 state 的初始數據,優先級高於 model 中的 state,默認爲 {}
。
其餘以 on
開頭的均爲鉤子函數,更多請參考 dva API。
當寫完 model 和組件後,須要將 model 和組件鏈接起來。dva 提供了 connect
方法,其實它就是 react-redux
的 connect
。用法以下:
1
2
3
4
5
6
7
8
9
10
11
12
|
import React from 'react';
import { connect } from 'dva';
const User = ({ dispatch, user }) => {
return (
<div></div>
)
}
export default connect(({ user }) => {
return user;
})(User);
|
connect 後的組件除了能夠獲取到 dispatch
和 state
,還能夠獲取到 location
和 history
。
effects
和 subscriptions
拋出的錯誤都會通過 onError
鉤子函數,因此能夠在 onError
中進行全局錯誤處理。
1
2
3
4
5
|
const app = dva({
onError(err, dispatch) {
console.error(err);
},
});
|
若是須要對某些 effects
進行特殊的錯誤處理,能夠使用 try catch
。
dva 集成了 isomorphic-fetch
用於處理異步請求,而且使用 dva-cli 初始化的項目中,已經在 ./src/utils/request.js
中對 fetch 進行了簡單的封裝,能夠在這裏根據服務端 API 的數據結構進行統一的錯誤處理。
固然若是你不想用 fetch,徹底能夠引入本身喜歡的第三方庫,沒有任何影響,打包時也不會將 isomorphic-fetch
打包進去。