react-native-easy-app 是一款為React Native App快速開發(fā)提供基礎(chǔ)服務(wù)的純JS庫(支持 IOS & Android),特別是在從0到1的項(xiàng)目搭建初期,至少可以為開發(fā)者減少30%的工作量。
react-native-easy-app 主要做了這些工作:
1. 對AsyncStorage進(jìn)行封裝,開發(fā)者只需幾行代碼即可實(shí)現(xiàn)一個(gè)持久化數(shù)據(jù)管理器。
2. 對fetch進(jìn)行封裝,使得開發(fā)者只需關(guān)注當(dāng)前App的前后臺交互邏輯和協(xié)議,定義好參數(shù)設(shè)置及解析邏輯即可。
3. 重新封裝了RN的View、Text、Image、FlatList 使用得這些控件在適當(dāng)?shù)臅r(shí)候支持事件或支持icon與文本,能有效減少布局中的嵌套邏輯。
4. 通過設(shè)置一個(gè)屏幕參考尺寸,重置XView、XText、XImage的尺寸,實(shí)現(xiàn)自動(dòng)多屏適配
可能有人覺得,RN的AsyncStorage本身就很簡單,自己封裝也就幾十行代碼的工作量,為什么還要使用第三方庫?
一千個(gè)人心中,有一千個(gè)哈姆雷特,也許我的封裝思路能給你帶來不一樣的啟發(fā)也未可知呢?
數(shù)據(jù)存儲(chǔ)(AsyncStorage)
RN平臺提供的AsyncStorage有一些基礎(chǔ)方法:setItem,getItem,removeItem,getAllKeys,這些是promise模式的并且AsyncStorage只支持對純字符串的存取,因此我們不便于直接在代碼中去直接調(diào)用這些方法,我們得對AsyncStorage做一次封裝,怎樣封裝能使我們更方便快捷的訪問本地存取呢?
我們來看下通過 react-native-easy-app 庫的XStorage,我們可以怎樣訪問AsyncStorage:
1、核心代碼實(shí)現(xiàn)
import { XStorage } from 'react-native-easy-app';
import { AsyncStorage } from 'react-native';
let RNStorage = { // 自定義對象
hasLogin: undefined,
customerId: undefined,
userInfo: undefined
};
XStorage.initStorage(RNStorage, AsyncStorage, () => { // 初始化自定義數(shù)據(jù)管理器
RNStorage.customerId = '123456';
RNStorage.hasLogin = true;
RNStorage.userInfo = {name: 'zhangsan', age: 30};
console.log(JSON.stringify(RNStorage)) // 打印數(shù)據(jù)管理器的內(nèi)容
})
執(zhí)行完上面的代碼后我們看看控制臺輸出:
再通過Root Explorer 查看一下當(dāng)前App的data/data/{package}/database 下數(shù)據(jù)表的內(nèi)容:
??什么?上面的代碼中并沒有做任何數(shù)據(jù)庫的存儲(chǔ)操作啊,為什么賦值給RNStorage的數(shù)據(jù)卻被存到了本地?cái)?shù)據(jù)庫中呢?我們先看上面的代碼中做了什么:
- 定義了一個(gè)自定義對象RNStorage
- 將自定義對象傳給XStorage.initStorage 進(jìn)行初始化
- 在初始化完成后對RNStorage的屬性進(jìn)行了賦值
- 打印RNStorage的內(nèi)容
由此可見,數(shù)據(jù)的存儲(chǔ)操作必定是上面的第2、3步引起的。我們進(jìn)入XStorage的源碼看看,里面做了什么:
- 源代碼 1
Object.keys(targetObj).map(key => {
const keyStr = newKey(Tag, key);
Object.defineProperty(targetObj, key, {
get: () => {
return this[keyStr]
},
set: (value) => {
try {
this[keyStr] = value;
const valueStr = (typeof value === 'object') ? JSON.stringify(value) : String(value);
keyValuesPairs.push([keyStr, valueStr])
} catch (exception) {
console.log(exception && exception.message);
}
},
})
});
setInterval(() => {
if (!isEmpty(keyValuesPairs)) {
let saveDataArray = [...keyValuesPairs];
keyValuesPairs = []; //清空原鍵值對數(shù)組
AsyncStorage.multiSet(saveDataArray, () => {
dataChangedCallback && dataChangedCallback(saveDataArray)
});
}
}, 2500)
- 源代碼 2
const Keys = Object.keys(storageObj);
const StorageKeys = Keys.map(key => newKey(Tag, key));
// 初始化時(shí),將AsyncStorage中的數(shù)據(jù)一次性讀取到內(nèi)存中
AsyncStorage.multiGet(StorageKeys).then(keyValuePairs => {
keyValuePairs.map(([keyStr, value]) => {
let [, key] = keyStr.split(splitTag);
if (persistTag !== key && !isEmpty(value)) {
storageObj[key] = convertData(value)
}
});
setTimeout(() => initializedCallback(), 100)
}).catch(error => {
console.log(error)
})
哦,原來 XStorage 通過getter、setter生成器,將用戶自定義的 RNStorage 的各屬與 AsyncStorage 的數(shù)據(jù)表各字段的值進(jìn)行了關(guān)聯(lián)形成了一個(gè)綁定關(guān)系,在當(dāng)用戶對 RNStorage 的各屬性進(jìn)行賦值、取值操作的時(shí)候,實(shí)際上會(huì)觸發(fā)getter、setter生成器,相應(yīng)的會(huì)對 AsyncStorage 中的數(shù)據(jù)表進(jìn)行讀寫操作。
效率與性能的平衡
- <讀> 在初始化XStorage的時(shí)候就將AsyncStorage中的所有字段一次性讀取到 RNStorage 對象中,以后續(xù)讀取屬性時(shí),并不需要經(jīng)過AsyncStorage,而是直接返回 RNStorage的屬性。
- <寫> 在開發(fā)者修改XStorage的屬性值時(shí),會(huì)先將目標(biāo)數(shù)據(jù)賦值給XStorage的屬性,然后再異步通過AsyncStorage將目標(biāo)數(shù)據(jù)寫入到數(shù)據(jù)庫中(考慮到數(shù)據(jù)寫入的效率與性能問題,目前的處理方式為:每次數(shù)值的變更都會(huì)記錄下來,定時(shí)程序每隔2.5秒進(jìn)行一次數(shù)據(jù)批量寫入操作),但這個(gè)絲毫不會(huì)影響App對數(shù)據(jù)的操作,因?yàn)镽NStorage中的數(shù)據(jù)是實(shí)時(shí)且同步的。
至此就完全清楚了,是不是很簡單?開發(fā)者通過 react-native-easy-app 只需定義一個(gè)全局可導(dǎo)出的 RNStorage對象(命名隨意,并定義好App所需的各屬性字段),然后在App啟動(dòng)的時(shí)候通過XStorage初始化一次RNStorage即可,以后直接訪問RNStorage中的屬性值就行了(所有對RNStorage屬性的修改都會(huì)被自動(dòng)同步到AsyncStorage中),完全是一勞永逸啊。。。
react-native-easy-app 詳解與使用之(二) fetch
想進(jìn)一步了解,請移步至 npm 或github查看 react-native-easy-app,有源碼及使用示例,待大家一探究竟,歡迎朋友們 Star!