本地数据存储指的是将数据存储在设备中,在需要数据的时候调用,数据并不会因为应用退出,或者网络断开而无法获取。在React Native中常用的存储方式有两种:
- AsyncStorage:类似iOS中的NSUserDefault,存放在plist文件中,官方推荐由React Native中文网封装维护的react-native-storage模块
-
Realm: 新的移动端数据库王者,据说性能甚至比单独无封装的SQLite还要快
如果你的应用数据量不大,仅仅需要存储几个用户配置的信息,就用AsyncStorage,否则就用Realm,如何抉择就像你选择NSUserDefault还是SQLite一样
下面举例用到的两个场景
场景1:用户通过用户名和密码登录,返回token,后续的接口请求中,需在请求头部带上token,服务端根据token来识别用户。
一 、安装react-native-storage并全局范围内创建一个storage实例
npm install react-native-storage --save
import { AsyncStorage } from 'react-native';
import Storage from 'react-native-storage';
var storage = new Storage({
size: 1000,
storageBackend: AsyncStorage,
defaultExpires: null,
enableCache: true,
})
// 全局变量
global.storage = storage
二 、用户登录,存储Token
fetch_login = () => {
let params = {
account: this.username,
password: this.password,
client_secret: config.app_client_secret,
client_id: config.app_client_id
}
passport_fetch('users/signin', 'POST', params).then(
(data) => {
//存储用户Token
global.storage.save({
key:'token',
data: data.access_token,
expires: null
});
this.refs.toast.show('登录成功');
this.fetchUserInfo()
}
).catch(
err=>{
this.refs.toast.show(err);
}
)
}
三 、接口请求时获取存储的Token信息
passport_fetch 是与帐号相关的网络请求接口,调用时候会从storage获取存储的Token并放入请求头部
const passport_fetch = async (url, method, params = '') => {
//获取存储Token
let token= await global.storage.load({
key:'token'
})
let header = {
"Content-Type": "application/json;charset=UTF-8",
'platform': 2,
};
if (token.length) {
header['Authorization'] = 'Bearer ' + token
}
return new Promise(function (resolve, reject) {
fetch(common_url + url, {
method: method,
headers: header,
body:JSON.stringify(params)
}).then((response) => response.json())
.then(checkStatus)
.then((responseData) => {
resolve(responseData['data']);
})
.catch( (err) => {
console.log('err:',url, err);
reject(err);
});
});
}
这里需注意的是存储数据的获取,storage
的load
是异步的,正常header以及请求只能写在其then
方法中,才能保证请求是在获取到数据之后才进行,如果要保证同步的写法,这里可以采用await伪同步的方式,同时整个函数必须是async的,最后返回一个Promise,比如登录后获取用户信息则会自动带上Token数据
fetchUserInfo = () => {
passport_fetch('users/me', 'GET').then(
() => {
this.refs.toast.show('获取信息成功');
}
).catch(
err=>{
this.refs.toast.show(err);
}
)
}
场景2:app首页加载时候先显示上次请求的数据,避免接口数据请求未返回前页面无数据的尴尬情况
在首页js文件中添加如下代码:
constructor(props) {
super(props)
this.state = {
dataList: this.loadFromLocal(),
}
...
}
//加载缓存数据
loadFromLocal = async () => {
let list= await storage.load({
key:'recommendList'
})
this.setState({
dataList: list,
})
}
fetchRequest('games/recommend', 'GET').then(
data => {
let newList = data.map((item) => {
return {
imageUrl: item.icon_url,
...
}
})
for (let i = 0; i < newList.length; i++) {
newList[i].id = i
}
this.setState({
dataList: newList,
refreshState: RefreshState.Idle,
})
storage.save({
key:'recommendList',
data: newList,
expires: null
})
}
)