React Native中Storage使用詳解和封裝

React Native中Storage使用詳解和封裝

在移動端開發中,數據庫存儲肯定是避免不了的需求,在iOS中,我們也經常使用NSUserDefault單利類來存儲一些簡單的用戶信息等數據,在web開發中我們經常使用LocalStorage來存儲簡單數據,在React Native中,我們可以選擇直接使用官方推薦的數據存儲組件AsyncStorage組件,但是有時候使用起來還是不夠簡單,功能不夠多,這時我們就會選擇封裝一個storage,我們選擇使用三方的react-native-storage 來進一步封裝

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 --save
  • import Storage from 'react-native-storage'
  • import { AsyncStorage } from 'react-native'
  • import {sync} from './sync'

如何封裝

這里封裝storage,我們根據官方文檔的建議,我們將采用單利模式來進行封裝,單利模式對于iOS開發的同學們肯定不陌生,其實web開發也有單例模式,是常用開發模式中的一種

  • 初始化

首先我們得創建一個storage全局單利對象

代碼如下:

const createStorage = () => {

  storage = new Storage({
    // 最大容量,默認值1000條數據循環存儲
    size: size,

    // 存儲引擎:對于RN使用AsyncStorage,對于web使用window.localStorage
    // 如果不指定則數據只會保存在內存中,重啟后即丟失
    storageBackend: AsyncStorage,

    // 數據過期時間,默認一整天(1000 * 3600 * 24 毫秒),設為null則永不過期
    defaultExpires: defaultExpires,

    // 讀寫時在內存中緩存數據。默認啟用。
    enableCache: true,

    // 如果storage中沒有相應數據,或數據已過期,
    // 則會調用相應的sync方法,無縫返回最新數據。
    // sync方法的具體說明會在后文提到
    // 你可以在構造函數這里就寫好sync的方法
    // 或是在任何時候,直接對storage.sync進行賦值修改
    // 或是寫到另一個文件里,這里require引入
    sync: sync
  })
}
  • 判斷這個storage單利對象是否存在,不存在就創建一個
const initStorage = () => {
  if (!storage) {
    createStorage()
  }
}
  • 完善storage 增刪改查等功能API

核心代碼

const _storage = {

  // 使用key來保存數據。這些數據一般是全局獨有的,常常需要調用的。
  // 除非你手動移除,這些數據會被永久保存,而且默認不會過期。
  save(key, obj) {
    initStorage()
    storage.save({
      key: key,  // 注意: 請不要在key中使用_下劃線符號!
      data: obj,
      // 如果不指定過期時間,則會使用defaultExpires參數
      // 如果設為null,則永不過期
      expires: defaultExpires
    })
  },

  // 取數據
  load(key, callBack) {
    initStorage()
    storage.load({
      key: key,
      // autoSync(默認為true)意味著在沒有找到數據或數據過期時自動調用相應的sync方法
      autoSync: true,
      // syncInBackground(默認為true)意味著如果數據過期,
      // 在調用sync方法的同時先返回已經過期的數據。
      // 設置為false的話,則始終強制返回sync方法提供的最新數據(當然會需要更多等待時間)。
      syncInBackground: true,
      // 你還可以給sync方法傳遞額外的參數
      syncParams: {
        extraFetchOptions: { // 各種參數
        },
        someFlag: true,
      }
    }).then(ret => {
      // 如果找到數據,則在then方法中返回
      // 注意:這是異步返回的結果(不了解異步請自行搜索學習)
      // 你只能在then這個方法內繼續處理ret數據
      // 而不能在then以外處理
      // 也沒有辦法“變成”同步返回
      // 你也可以使用“看似”同步的async/await語法
      callBack && callBack(ret)
      return ret
    }).catch(err => {
      //如果沒有找到數據且沒有sync方法,
      //或者有其他異常,則在catch中返回
      console.warn(err.message);
      switch (err.name) {
        case 'NotFoundError':
          // TODO
          break
        case 'ExpiredError':
          // TODO
          break
      }
    })
  },

  // 獲取某個key下的所有id(僅key-id數據)
  getIdsForKey(id, callback) {
    initStorage()
    storage.getIdsForKey(id).then(ids => {
      callback && callback(ids)
    })
  },

  // 獲取某個key下的所有數據(僅key-id數據)
  getAllDataForKey(key, callback) {
    initStorage()
    storage.getAllDataForKey(key).then(users => {
      callback && callback(users)
    })
  },

  // !! 清除某個key下的所有數據(僅key-id數據)
  clearMapForKey(key) {
    initStorage()
    storage.clearMapForKey(key)
  },

  // 刪除單個數據
  remove(key) {
    initStorage()
    storage.remove({
      key: key
    })
  },

  // !! 清空map,移除所有"key-id"數據(但會保留只有key的數據)
  clearMap() {
    initStorage()
    storage.clearMap()
  }
}
  • 導出單利類
export {_storage as storage}

注意: 上面的基本使用方式官方文檔也都說的很詳細了,這里重點介紹下,new Storage 中的 sync: sync

這個用法是說:調用storage.load時,如果本地并沒有存儲相應的user數據,那么會自動觸發storage.sync.user去遠程網絡請求獲取user數據并無縫返回過來

  • 創建sync 文件,同步遠程數據(刷新)

核心代碼

/**
 * Created by guangqiang on 2017/11/15.
 */
import {storage} from './index'

/**
 * sync方法的名字必須和所存數據的key完全相同
 * 方法接受的參數為一整個object,所有參數從object中解構取出
 * 這里可以使用promise。或是使用普通回調函數,但需要調用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) {
          // 根據syncParams中的額外參數做對應處理
        }

        // 成功則調用resolve
        resolve && resolve(json.user)
      } else {
        // 失敗則調用reject
        reject && reject(new Error('data parse error'))
      }
    }).catch(err => {
      console.warn(err)
      reject && reject(err)
    })
  }
}

export {sync}

附加功能

  • 讀取批量數據
// 使用和load方法一樣的參數讀取批量數據,但是參數是以數組的方式提供。
// 會在需要時分別調用相應的sync方法,最后統一返回一個有序數組。
storage.getBatchData([
    { key: 'loginState' },
    { key: 'checkPoint', syncInBackground: false },
    { key: 'balance' },
    { key: 'user', id: '1009' }
])
.then(results => {
  results.forEach( result => {
    console.log(result);    
  })
})
  
//根據key和一個id數組來讀取批量數據
storage.getBatchDataWithIds({
  key: 'user', 
  ids: ['1001', '1002', '1003']
})
.then( ... )

這兩個方法除了參數形式不同,還有個值得注意的差異。getBatchData會在數據缺失時挨個調用不同的sync方法(因為key不同)。但是getBatchDataWithIds卻會把缺失的數據統計起來,將它們的id收集到一個數組中,然后一次傳遞給對應的sync方法(避免挨個查詢導致同時發起大量請求),所以你需要在服務端實現通過數組來查詢返回,還要注意對應的sync方法的參數處理(因為id參數可能是一個字符串,也可能是一個數組的字符串)

使用方式

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開源項目OneM【500+ star】地址(按照企業開發標準搭建框架完成開發的):https://github.com/guangqiang-liu/OneM:歡迎小伙伴們 star
  • 作者簡書主頁:包含60多篇RN開發相關的技術文章http://www.lxweimin.com/u/023338566ca5 歡迎小伙伴們:多多關注多多點贊
  • 作者React Native QQ技術交流群:620792950 歡迎小伙伴進群交流學習
  • 友情提示:在開發中有遇到RN相關的技術問題,歡迎小伙伴加入交流群(620792950),在群里提問、互相交流學習。交流群也定期更新最新的RN學習資料給大家,謝謝大家支持!

小伙伴們掃下方二維碼加入RN技術交流QQ群

QQ群二維碼,500+ RN工程師在等你加入哦
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容