React Native中Storage使用詳解和封裝
在移動端開發(fā)中,數(shù)據(jù)庫存儲肯定是避免不了的需求,在iOS中,我們也經(jīng)常使用NSUserDefault單利類來存儲一些簡單的用戶信息等數(shù)據(jù),在web開發(fā)中我們經(jīng)常使用LocalStorage來存儲簡單數(shù)據(jù),在React Native中,我們可以選擇直接使用官方推薦的數(shù)據(jù)存儲組件AsyncStorage組件,但是有時候使用起來還是不夠簡單,功能不夠多,這時我們就會選擇封裝一個storage,我們選擇使用三方的react-native-storage 來進(jìn)一步封裝
react-native-storage 官方文檔
https://github.com/sunnylqm/react-native-storage/blob/master/README-CHN.md
作者提供封裝好的storage組件Demo示例
https://github.com/guangqiang-liu/react-native-storage-Demo
安裝react-native-storage組件
npm install react-native-storage --saveimport Storage from 'react-native-storage'import { AsyncStorage } from 'react-native'import {sync} from './sync'
如何封裝
這里封裝storage,我們根據(jù)官方文檔的建議,我們將采用單利模式來進(jìn)行封裝,單利模式對于iOS開發(fā)的同學(xué)們肯定不陌生,其實(shí)web開發(fā)也有單例模式,是常用開發(fā)模式中的一種
- 初始化
首先我們得創(chuàng)建一個storage全局單利對象
代碼如下:
const createStorage = () => {
storage = new Storage({
// 最大容量,默認(rèn)值1000條數(shù)據(jù)循環(huán)存儲
size: size,
// 存儲引擎:對于RN使用AsyncStorage,對于web使用window.localStorage
// 如果不指定則數(shù)據(jù)只會保存在內(nèi)存中,重啟后即丟失
storageBackend: AsyncStorage,
// 數(shù)據(jù)過期時間,默認(rèn)一整天(1000 * 3600 * 24 毫秒),設(shè)為null則永不過期
defaultExpires: defaultExpires,
// 讀寫時在內(nèi)存中緩存數(shù)據(jù)。默認(rèn)啟用。
enableCache: true,
// 如果storage中沒有相應(yīng)數(shù)據(jù),或數(shù)據(jù)已過期,
// 則會調(diào)用相應(yīng)的sync方法,無縫返回最新數(shù)據(jù)。
// sync方法的具體說明會在后文提到
// 你可以在構(gòu)造函數(shù)這里就寫好sync的方法
// 或是在任何時候,直接對storage.sync進(jìn)行賦值修改
// 或是寫到另一個文件里,這里require引入
sync: sync
})
}
- 判斷這個storage單利對象是否存在,不存在就創(chuàng)建一個
const initStorage = () => {
if (!storage) {
createStorage()
}
}
- 完善storage 增刪改查等功能API
核心代碼
const _storage = {
// 使用key來保存數(shù)據(jù)。這些數(shù)據(jù)一般是全局獨(dú)有的,常常需要調(diào)用的。
// 除非你手動移除,這些數(shù)據(jù)會被永久保存,而且默認(rèn)不會過期。
save(key, obj) {
initStorage()
storage.save({
key: key, // 注意: 請不要在key中使用_下劃線符號!
data: obj,
// 如果不指定過期時間,則會使用defaultExpires參數(shù)
// 如果設(shè)為null,則永不過期
expires: defaultExpires
})
},
// 取數(shù)據(jù)
load(key, callBack) {
initStorage()
storage.load({
key: key,
// autoSync(默認(rèn)為true)意味著在沒有找到數(shù)據(jù)或數(shù)據(jù)過期時自動調(diào)用相應(yīng)的sync方法
autoSync: true,
// syncInBackground(默認(rèn)為true)意味著如果數(shù)據(jù)過期,
// 在調(diào)用sync方法的同時先返回已經(jīng)過期的數(shù)據(jù)。
// 設(shè)置為false的話,則始終強(qiáng)制返回sync方法提供的最新數(shù)據(jù)(當(dāng)然會需要更多等待時間)。
syncInBackground: true,
// 你還可以給sync方法傳遞額外的參數(shù)
syncParams: {
extraFetchOptions: { // 各種參數(shù)
},
someFlag: true,
}
}).then(ret => {
// 如果找到數(shù)據(jù),則在then方法中返回
// 注意:這是異步返回的結(jié)果(不了解異步請自行搜索學(xué)習(xí))
// 你只能在then這個方法內(nèi)繼續(xù)處理ret數(shù)據(jù)
// 而不能在then以外處理
// 也沒有辦法“變成”同步返回
// 你也可以使用“看似”同步的async/await語法
callBack && callBack(ret)
return ret
}).catch(err => {
//如果沒有找到數(shù)據(jù)且沒有sync方法,
//或者有其他異常,則在catch中返回
console.warn(err.message);
switch (err.name) {
case 'NotFoundError':
// TODO
break
case 'ExpiredError':
// TODO
break
}
})
},
// 獲取某個key下的所有id(僅key-id數(shù)據(jù))
getIdsForKey(id, callback) {
initStorage()
storage.getIdsForKey(id).then(ids => {
callback && callback(ids)
})
},
// 獲取某個key下的所有數(shù)據(jù)(僅key-id數(shù)據(jù))
getAllDataForKey(key, callback) {
initStorage()
storage.getAllDataForKey(key).then(users => {
callback && callback(users)
})
},
// !! 清除某個key下的所有數(shù)據(jù)(僅key-id數(shù)據(jù))
clearMapForKey(key) {
initStorage()
storage.clearMapForKey(key)
},
// 刪除單個數(shù)據(jù)
remove(key) {
initStorage()
storage.remove({
key: key
})
},
// !! 清空map,移除所有"key-id"數(shù)據(jù)(但會保留只有key的數(shù)據(jù))
clearMap() {
initStorage()
storage.clearMap()
}
}
- 導(dǎo)出單利類
export {_storage as storage}
注意: 上面的基本使用方式官方文檔也都說的很詳細(xì)了,這里重點(diǎn)介紹下,new Storage 中的 sync: sync
這個用法是說:調(diào)用storage.load時,如果本地并沒有存儲相應(yīng)的user數(shù)據(jù),那么會自動觸發(fā)storage.sync.user去遠(yuǎn)程網(wǎng)絡(luò)請求獲取user數(shù)據(jù)并無縫返回過來
- 創(chuàng)建sync 文件,同步遠(yuǎn)程數(shù)據(jù)(刷新)
核心代碼
/**
* Created by guangqiang on 2017/11/15.
*/
import {storage} from './index'
/**
* sync方法的名字必須和所存數(shù)據(jù)的key完全相同
* 方法接受的參數(shù)為一整個object,所有參數(shù)從object中解構(gòu)取出
* 這里可以使用promise?;蚴鞘褂闷胀ɑ卣{(diào)函數(shù),但需要調(diào)用resolve或reject
* @type {{user: ((params))}}
*/
const sync = {
user(params) {
let { id, resolve, reject, syncParams: { extraFetchOptions, someFlag } } = params
fetch('http://www.baidu.com', {
method: 'GET',
body: 'id=' + id,
...extraFetchOptions,
}).then(response => {
return response.json()
}).then(json => {
//console.log(json)
if(json && json.user){
storage.save({
key: 'user',
data: json.user
})
if (someFlag) {
// 根據(jù)syncParams中的額外參數(shù)做對應(yīng)處理
}
// 成功則調(diào)用resolve
resolve && resolve(json.user)
} else {
// 失敗則調(diào)用reject
reject && reject(new Error('data parse error'))
}
}).catch(err => {
console.warn(err)
reject && reject(err)
})
}
}
export {sync}
附加功能
- 讀取批量數(shù)據(jù)
// 使用和load方法一樣的參數(shù)讀取批量數(shù)據(jù),但是參數(shù)是以數(shù)組的方式提供。
// 會在需要時分別調(diào)用相應(yīng)的sync方法,最后統(tǒng)一返回一個有序數(shù)組。
storage.getBatchData([
{ key: 'loginState' },
{ key: 'checkPoint', syncInBackground: false },
{ key: 'balance' },
{ key: 'user', id: '1009' }
])
.then(results => {
results.forEach( result => {
console.log(result);
})
})
//根據(jù)key和一個id數(shù)組來讀取批量數(shù)據(jù)
storage.getBatchDataWithIds({
key: 'user',
ids: ['1001', '1002', '1003']
})
.then( ... )
這兩個方法除了參數(shù)形式不同,還有個值得注意的差異。getBatchData會在數(shù)據(jù)缺失時挨個調(diào)用不同的sync方法(因?yàn)閗ey不同)。但是getBatchDataWithIds卻會把缺失的數(shù)據(jù)統(tǒng)計(jì)起來,將它們的id收集到一個數(shù)組中,然后一次傳遞給對應(yīng)的sync方法(避免挨個查詢導(dǎo)致同時發(fā)起大量請求),所以你需要在服務(wù)端實(shí)現(xiàn)通過數(shù)組來查詢返回,還要注意對應(yīng)的sync方法的參數(shù)處理(因?yàn)閕d參數(shù)可能是一個字符串,也可能是一個數(shù)組的字符串)
使用方式
import {storage} from './storage'
componentDidMount() {
let obj = {}
obj.name = '張三'
obj.age = 20
obj.sex = 'man'
// 存
storage.save('userInfo', obj)
// 取
storage.load('userInfo', (data) => {
alert(data.name)
})
}
更多文章
- 作者React Native開源項(xiàng)目OneM【500+ star】地址(按照企業(yè)開發(fā)標(biāo)準(zhǔn)搭建框架完成開發(fā)的):https://github.com/guangqiang-liu/OneM:歡迎小伙伴們 star
- 作者簡書主頁:包含60多篇RN開發(fā)相關(guān)的技術(shù)文章http://www.itdecent.cn/u/023338566ca5 歡迎小伙伴們:多多關(guān)注,多多點(diǎn)贊
- 作者React Native QQ技術(shù)交流群:620792950 歡迎小伙伴進(jìn)群交流學(xué)習(xí)
- 友情提示:在開發(fā)中有遇到RN相關(guān)的技術(shù)問題,歡迎小伙伴加入交流群(620792950),在群里提問、互相交流學(xué)習(xí)。交流群也定期更新最新的RN學(xué)習(xí)資料給大家,謝謝大家支持!
小伙伴們掃下方二維碼加入RN技術(shù)交流QQ群
