React Native 在使用者網路故障時自動調取快取

Bougie發表於2018-05-29

App往往都有快取功能,例如常見的新聞類應用,如果你關閉網路,你上次開啟App載入的資料還在,只是不能載入新的資料了。

我的部落格bougieblog.cn,歡迎前來尬聊。

image

集中處理請求

如果你fetch資料的頁面有多個,不集中處理的話每個頁面都要單獨進行快取處理。那麼,如何對http請求進行集中處理?
在WebApp中常見的做法就是將請求放在action裡面,例如VuexRedux。但是在業務邏輯較少的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

請求呼叫

我們可以模仿一下VuexRedux的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
    })
}
// ...

複製程式碼

原文地址:React Native在使用者網路故障時自動調取快取

相關文章