首先先來講一下爲何要用fetch而不是axios吧,主要有如下兩點:前端
爲何要單獨說一下fetch的response呢,我的認爲這一點既是fetch的缺點又是fetch的優勢,咱們先來對比一下正常的請求fetch和axios的區別node
// fetch
fetch(url)
.then(res => { // 第一層res
res.json() // 須要json事後纔是咱們想要的數據
.then(r => { // 第二層res
console.log(r) // 獲取到最後數據
})
});
// axios
axios(url)
.then(res=>{ // 第一層res
console.log(res); // 獲取到咱們想要的數據
});
複製代碼
如上面所示,咱們須要先對fetch的res進行res.json()以後纔拿到咱們想要的json數據,而axios幫咱們作了,使用起來更簡單~react
這算是一個缺點吧~可是!!!咱們經過封裝徹底能夠解決的,接下來就是爲啥這也是fetch的優勢了,首先來講說爲啥fetch須要兩層才能夠,第一層進行的是res.json(),由於fetch的response是一個綜合各類方法的對象,並非請求的數據,也就是說其實fetch不只能夠是一個json對象,還能夠是其餘不少的,若是咱們須要的是json對象,就res.json(),若是須要的是文本字符串,能夠res.text(),它還能夠直接獲取blob內容,res.blob()。綜上所述,fetch是真的真的很強大,就看你擅不擅長封裝使用了。ios
事先聲明,我上面吹了那麼久,其實我我的以爲我也不算太會使用哈,下面的封裝也就是簡單的封裝,各位看官按需使用,能夠在我基礎之上針對本身的項目進行更好的封裝,或者就直接本身封裝就能夠了。git
上面講了fetch的幾個缺點,其實這些缺點都是能夠經過封裝以及插件來進行彌補的。github
import fetch from 'isomorphic-unfetch';
import qs from 'query-string';
import { filterObject } from './util';
// initial fetch
const nextFetch = Object.create(null);
// browser support methods
// ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PATCH', 'PUT']
const HTTP_METHOD = ['get', 'post', 'put', 'patch', 'delete'];
// can send data method
const CAN_SEND_METHOD = ['post', 'put', 'delete', 'patch'];
HTTP_METHOD.forEach(method => {
// is can send data in opt.body
const canSend = CAN_SEND_METHOD.includes(method);
nextFetch[method] = (path, { data, query, timeout = 5000 } = {}) => {
let url = path;
const opts = {
method,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json'
},
credentials: 'include',
timeout,
mode: 'same-origin',
cache: 'no-cache'
};
if (query) {
url += `${url.includes('?') ? '&' : '?'}${qs.stringify(
filterObject(query, Boolean),
)}`;
}
if (canSend && data) {
opts.body = qs.stringify(filterObject(data, Boolean));
}
console.info('Request Url:', url);
return fetch(url, opts)
.then(res => res.json())
.then(({ errcode = 0, errmsg, data }) => {
if (errcode !== 0) {
const err = new Error(errmsg);
err.message = errmsg;
err.code = errcode;
err.data = data;
throw err;
}
return data;
});
};
});
export default nextFetch;
複製代碼
封裝完以後的使用:express
// /redux/sagas/user/userList.js
...
import nextFetch from '../../../core/nextFetch';
export function* userList() {
while (true) {
yield take(FETCH_USER_LIST);
try {
// 新寫法
const data = yield nextFetch.get(api.getUserList);
// 原來的寫法
// const res = yield fetch(api.getUserList);
// const { data } = yield res.json();
yield put(fetchUserListDataSuccess(data));
} catch (error) {
console.log(error.code, error.message, error.data);
yield put(fetchUserListDataFali(error));
}
}
}
複製代碼
爲何使用的是
isomorphic-unfetch
, 由於Next.js是服務端渲染,這個標榜的是先後端都通用~之前我用的服務端渲染框架由於是分離的,先後端使用的是不一樣的fetch(前端是whatwg-fetch,後端是node-fetch)。json
上面是我本身的封裝方式,我默認後端返回的是一個json格式的數據,而後裏面有三個字段
{ data, errcode, errmsg }
,而且成功的響應code = 0
。小夥伴們根據本身的項目結構適當進行更改。redux
這個就很簡單了,redux的中間件系統,爲何增長中間件呢,由於上面咱們增長了fetch的error處理,那麼咱們就能夠對失敗的請求在中間件這個地方進行提早處理~axios
// /redux/store.js
import userMiddleware from '../middlewares/client/user';
...
// 增長redux中間件
const bindMiddleware = (middleware) => {
// add route middleware
middleware.push(userMiddleware);
...
return applyMiddleware(...middleware);
};
// /middles/client/user.js
import { message } from 'antd';
import {
FETCH_USER_LIST_FAIL
} from '../../constants/ActionTypes';
export default ({ getState }) => next => action => {
// redux中間件
const ret = next(action);
switch (action.type) {
case FETCH_USER_LIST_FAIL: {
message.error('獲取用戶列表失敗, 請稍後重試');
break;
}
default:
}
return ret;
};
複製代碼
效果如圖所示:
今天這個就很簡單了,也不是什麼高級的東西,都是隨手拿來用的,只不過封裝起來方便使用一些,感受這個腳手架到這真的能夠直接進行項目的開發了,可能還差一個前端日誌功能吧,下面有時間寫寫前端日誌~