安裝(官方文檔:https://umijs.org/zh):
yarn global add umi
使用:
使用umi -v可查看版本,確保全局安裝沒問題
umi g page <文件名>
//創建包含目錄的頁面home/index.js home/index.css
umi g page home/index
//創建dva modle文件(如果項目是用yarn create umi創建的則無法使用該命令)
umi g dva:modle <文件名> //umi+dva的項目中可以不用在modle文件中指定namespace,默認取文件名
通常情況下我們會使用yarn create umi來創建項目結構,在創建的時候會提示你做出一些關於項目的選擇:
確定後,會根據你的選擇自動創建好目錄和文件,然後yarn install安裝依賴。
常用配置:
更改主題色和自定義less全局變量,在.umirc文件中加入:
"theme": {
"primary-color": "#1DA57A",//更改主題色
"main_width": "1440px",//自定義全局樣式變量
},
啓用組件按需加載,在.umirc文件umi-plugin-react插件配置中加入dynamicImport配置(同樣基於react-loadble插件實現的):
dynamicImport: {
webpackChunkName: true,//是否打包時將分割出來的文件命名讓其有意義
loadingComponent: './components/Loading.js',//loading組件
level: 2, //根據幾級路由做按需編譯,值越大按需編譯的越詳細,默認是會根據路由層級來動態判斷等級的,所以一般可以不指定
},
項目默認語言umi-plugin-react插件配置設置:
locale: {
default: 'zh-CN'
},
umi-plugin-react插件配置還可以配置dva的immer,讓其在reducer中不需要再return修改後state,而是可以直接修改即可生效:
dva: {
immer: true,
hmr: true
},
//在reducer中:
reducer:{//不啓用immer
addCount(state, action){
state.count += 1
return state
}
}
reducer:{//啓用immer
addCount(state, action){
state.count += 1
}
}
//這只是簡單基本數據類型的改變實例,在某些情況下會讓你少寫更多代碼
解決瀏覽器緩存問題,當項目迭代一個版本更新部署到服務器時防止瀏覽器讀取之前的緩存文件,在.umirc中加入:
hash: true,//默認是false
//打包後的文件名會由xxx.async.js變爲xxx.0aee2612.async.js每build一次hash值都不一樣
跨域代理proxy:
proxy: {
'/server/api/': {
target: 'https://preview.pro.ant.design/',
changeOrigin: true,
pathRewrite: { '^/server': '' },
},
},
umi通過chainWebpack暴露出了webpack的配置,從而我們可以修改:
chainWebpack(config, { webpack }) {
config.module.rules.store.delete('eslint')//禁用eslint
}
//因爲不想修改node_modules,我也是通過打印config對象摸索,嘗試修改,果然成功。這裏因爲store是個Map類型的對象,所以只能用delete來刪除key
在原始dva項目中直接通過app.js中導出的dva實例對象即可獲取dispatch,但在umi中dva對象實例化配置過程全部是由umi自動生成,這裏umi將dva實例對象注入到了window.g_app._store中。
實際項目請求封裝示例:
// request.js
import axios from 'axios'
import { notification, message } from 'antd'
import history from 'umi/router';
const ipConfig = require('../apiConfig')
message.config({
top: 200,
duration: 3,
maxCount: 3,
})
/**
* 一、功能:
* 1. 統一攔截http錯誤請求碼;
* 2. 統一攔截業務錯誤代碼;
* 3. 統一設置請求前綴
* |-- 每個 http 加前綴 baseURL = /api,從配置文件中獲取 apiPrefix
*
* 二、引包:
* |-- axios:http 請求工具庫
* |-- notification:Antd組件 > 處理錯誤響應碼提示信息
* |-- history:dva/router對象,用於路由跳轉,錯誤響應碼跳轉相應頁面
* |-- store:dva中對象,使用裏面的 dispatch 對象,用於觸發路由跳轉
*/
// 設置全局參數,如響應超市時間,請求前綴等。
axios.defaults.timeout = 30000
if(process.env.NODE_ENV == 'development'){
// axios.defaults.baseURL = '/API'
axios.defaults.baseURL = ipConfig['dev']
}else{
axios.defaults.baseURL = ipConfig['build']
}
axios.defaults.withCredentials = true
// 狀態碼錯誤信息
const codeMessage = {
200: '服務器成功返回請求的數據。',
201: '新建或修改數據成功。',
202: '一個請求已經進入後臺排隊(異步任務)。',
204: '刪除數據成功。',
400: '發出的請求有錯誤,服務器沒有進行新建或修改數據的操作。',
401: '用戶沒有權限(令牌、用戶名、密碼錯誤)。',
403: '用戶得到授權,但是訪問是被禁止的。',
404: '發出的請求針對的是不存在的記錄,服務器沒有進行操作。',
406: '請求的格式不可得。',
410: '請求的資源被永久刪除,且不會再得到的。',
422: '當創建一個對象時,發生一個驗證錯誤。',
500: '服務器發生錯誤,請檢查服務器。',
502: '網關錯誤。',
503: '服務不可用,服務器暫時過載或維護。',
504: '網關超時。',
}
// 添加一個請求攔截器,用於設置請求過渡狀態
axios.interceptors.request.use((config) => {
const token = localStorage.user ? JSON.parse(localStorage.user).token : null
const visitToken = localStorage.visitToken
config.headers.token = token ? token : visitToken
return config
}, (error) => {
return Promise.reject(error)
})
// 添加一個返回攔截器
axios.interceptors.response.use((response) => {
return response
}, (error) => {
return Promise.reject(error)
})
export default function request (opt) {
if(!opt.data) opt.data = {}
if(opt.method == 'GET') opt.params = opt.data
// 調用 axios api,統一攔截
return axios(opt)
.then((response) => {
// >>>>>>>>>>>>>> 請求成功 <<<<<<<<<<<<<<
// if(process.env.NODE_ENV == 'development'){
// if(!response.data.status){
// notification.error({
// message: `${opt.url}-${status}`,
// description: 'msg: '+response.data.msg,
// })
// }else{
// notification.success({
// message: `${opt.url}-${status}`,
// description: 'msg: '+response.data.msg+' data:'+JSON.stringify(response.data.data),
// })
// }
// }
if(!response.data.status && (response.data.code == '000009' || response.data.code == '700000')) {//登陸過期
window.g_app._store.dispatch({
type: 'global/common',
payload:{showLoginModal: true}
})
message.info(response.data.msg)
}
return response.data;
})
.catch((error) => {
// >>>>>>>>>>>>>> 請求失敗 <<<<<<<<<<<<<<
// 請求配置發生的錯誤
if (!error.response) {
console.dir(error)
if(error.message.indexOf('timeout of')>-1) alert('請求超時!')
}
// 響應時狀態碼處理
const status = error.response.status;
const errortext = codeMessage[status] || error.response.statusText;
notification.error({
message: `請求錯誤- ${status}`,
description: errortext,
})
// if (status === 401) {
// history.push('/user/login')
// } else if (status === 403) {
// history.push('/exception/403')
// } else if (status <= 504 && status >= 500) {
// history.push('/exception/500')
// } else if (status >= 404 && status < 422) {
// history.push('/exception/404')
// }
// return { code: status, message: errortext }
})
}