App往往都有快取功能,例如常見的新聞類應用,如果你關閉網路,你上次開啟App載入的資料還在,只是不能載入新的資料了。
我的部落格bougieblog.cn,歡迎前來尬聊。
集中處理請求
如果你fetch資料的頁面有多個,不集中處理的話每個頁面都要單獨進行快取處理。那麼,如何對http請求進行集中處理?
在WebApp中常見的做法就是將請求放在action
裡面,例如Vuex
和Redux
。但是在業務邏輯較少的App中,我們往往可能不需要Redux
。這時就需要我們自己對集中請求進行封裝。
封裝AsyncStorage
AsyncStorage只能存取字串,我們需封裝一下,讓它能存取json
:
import { AsyncStorage } from 'react-native'
class Storage {
set({key, val}) {
return AsyncStorage.setItem(key, JSON.stringify(val))
}
get(key) {
return AsyncStorage.getItem(key).then(val => {
return JSON.parse(val)
})
}
remove(key) {
return AsyncStorage.removeItem(key)
}
clear() {
return AsyncStorage.clear()
}
}
export default new Storage()
複製程式碼
命名為storage.js
封裝公共請求函式
在網路故障時獲取storage裡的內容,網路良好時更新storage。
import axios from 'axios'
import storage from './storage'
import apiList from './apiList'
import {NetInfo, ToastAndroid} from 'react-native'
/**
* @param {String} api 介面名稱
* @param {Object} [replace={}] 替換url中的{}包裹的引數
* @param {Object} [data={}] 傳給服務端的資料
* @param {Object} [headers={}] http請求頭引數
* @return {Promise} 返回promise
*/
const $http = async ({api, replace, data, headers}) => {
let regExp = /\{ *([\w_\-]+) *\}/g,
url = apiList[api].url,
replaceList = url.match(regExp)
if(replaceList) {
replaceList.forEach(i => {
let key = i.slice(1, i.length - 1)
url = url.replace(i, replace[key])
})
}
let netStatu = await NetInfo.getConnectionInfo()
let result
if(['none', 'unknown'].includes(netStatu.type)) {
ToastAndroid.show('請檢查您的網路連線', ToastAndroid.SHORT)
result = await storage.get(api) || null
} else {
try {
let {data} = await axios({
method: apiList[api].method,
url: url,
data: data,
headers: headers
})
result = data
} catch(err) {
ToastAndroid.show(err.message, ToastAndroid.SHORT)
result = await storage.get(api) || null
}
await storage.set({
key: api,
val: result
})
}
return result
}
export default $http
複製程式碼
命名為service.js
請求配置
為標示請求唯一性,我們需給每個請求取一個名稱:
export default {
GET_NEWS_LIST: {
url: '/my/news?pageNum={pageNum}&pageSize={pageSize}',
method: 'get'
}
}
複製程式碼
命名為apiList.js
請求呼叫
我們可以模仿一下Vuex
或Redux
的action:
import $http from './service'
export async function getNewsList(pageNum, pageSize) {
return await $http({
api: 'GET_NEWS_LIST',
replace: {
pageNum,
pageSize
}
})
}
複製程式碼
命名為serviceAction.js
呼叫:
import {getNewsList} from './serviceAction'
// ...
async componentDidMount() {
let newsList = await getNewsList(1)
this.setState({
newsList
})
}
// ...
複製程式碼