dva.js 上手

來源: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
  • mock 存放用於 mock 數據的文件;
  • public 通常用於存放靜態文件,打包時會被直接複製到輸出目錄(./dist);
  • src 文件夾用於存放項目源代碼;
    • asserts 用於存放靜態資源,打包時會通過 webpack 處理;
    • components 用於存放 React 組件,通常是該項目公用的無狀態組件;
    • models 用於存放模型文件
    • routes 用於存放須要 connect model 的路由組件;
    • services 用於存放服務文件,通常是網絡請求等;
    • utils 工具類庫
    • router.js 路由文件
    • index.js 項目的入口文件
    • index.css 通常是共用的樣式
  • .editorconfig 編輯器配置文件
  • .eslintrc ESLint配置文件
  • .gitignore Git忽略文件
  • .roadhogrc.mock.js Mock配置文件
  • .webpackrc 自定義的webpack配置文件,JSON格式,若是須要 JS 格式,可修改成 .webpackrc.js

antd 按需引入

先安裝 antd 和 babel-plugin-importjson

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 配置

自定義 antd 主題

能夠在 .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

CSS Modules

使用 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

如需 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

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

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

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 包含 putcall 和 select 三個字段,put 用於觸發 actioncall 用於調用異步處理邏輯,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' }

app

在 ./src/index.js 中能夠看到以下代碼:

1
2
import dva from 'dva';
const app = dva();

app 就是 dva 實例,建立實例時 dva 方法能夠傳入一些參數,以下:

  • history
  • initialState
  • onError
  • onAction
  • onStateChange
  • onReducer
  • onEffect
  • onHmr
  • extraReducers
  • extraEnhancers

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

connect

當寫完 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 打包進去。

參考連接

相關文章
相關標籤/搜索