React-Native 數(shù)據(jù)持久化探索

  • 使用RN也有一段時間了,但是卻未試過在RN項目中實現(xiàn)數(shù)據(jù)的持久化,雖然項目繼承了react-redux,但是數(shù)據(jù)存在于內(nèi)存中,用戶關閉APP后,需要重新初始化數(shù)據(jù),網(wǎng)上大多RN數(shù)據(jù)持久化都是將一些數(shù)據(jù)存在AsyncStorage中,但是卻打斷了與redux的聯(lián)系
  • Github上已經(jīng)有現(xiàn)成的redux-persist包以解決redux持久化問題,但在實際使用過程中,還有很多問題需要解決。具體來說,redux-persist這個包提供的是通用解決方案,也可以用于react.js,如果你要用在react-native中的話,需要指定AsyncStorage,另外,雖然它還額外提供了兩個transform插件redux-persist-transform-immutableredux-persist-immutable,但這兩個插件目前使用起來還是有問題沒有解決,為了盡快用上redux-persist,可以使用以下方案。
解決

在建立redux store時,除了常規(guī)會用到的各種中間件以外,我們需要額外引入redux-persist里的autoRehydrate增強器,然后啟動持久化。

Store.ts
import { applyMiddleware, createStore, compose } from 'redux';
import { autoRehydrate } from 'redux-persist';
import createSagaMiddleware from 'redux-saga';
// 中間件,作用:如果不使用該中間件,當我們dispatch一個action時,需要給dispatch函數(shù)傳入action對象;
// 但如果我們使用了這個中間件,那么就可以傳入一個函數(shù),這個函數(shù)接收兩個參數(shù):dispatch和getState。這個dispatch可以在將來的異步請求完成后使用,對于異步action很有用
import thunk from 'redux-thunk';
import logger from 'redux-logger';
// 引入reducer
import reducer from './reducer';
// 引入持久化配置文件
import ReduxPersist from '../config/ReduxPersist';
// 引入版本變化重新持久化文件
import RehydrationServices from '../config/RehydrationServices';
// 使用redux-thunk中間件,處理異步action,這里則不實用saga中間件
// const sagaMiddleware = createSagaMiddleware();
// let middleware:any = [];
// middleware.push(sagaMiddleware);

let store: any = {};
const createAppropriateStore =  createStore;

if (ReduxPersist.active) {
    // 如果配置中要求采用持久化
    const enhancers = compose(
      applyMiddleware(thunk, logger), // 加入thunk中間件和日志中間件
      autoRehydrate()
    );

    store = createAppropriateStore(
        reducer,
        enhancers
    );
    // 啟動持久化
    RehydrationServices.updateReducers(store);
} else {
    // 如果配置中不要求采用持久化
    store = createStore(
        reducer,
        applyMiddleware(thunk, logger)
    );
}

export default store;

ReduxPersist.ts 持久化配置文件
import { AsyncStorage } from 'react-native';

import immutablePersistenceTransform from '../redux/ImmutablePersistenceTransform';
import { persistentStoreBlacklist } from '../redux/reducer';

const REDUX_PERSIST: any = {
  active: true, // 是否采用持久化策略
  reducerVersion: '1.0.0',  // reducer版本,如果版本不一致,將刷新整個持久化倉庫
  storeConfig: {
    storage: AsyncStorage,  // 采用本地異步存儲,react-native必須
    blacklist: persistentStoreBlacklist,  // 從根reducer獲取黑名單,黑名單中的reducer不進行持久化保存
    transforms: [immutablePersistenceTransform],  // 重要,因為redux是immutable不可變的,此處必須將常規(guī)數(shù)據(jù)做變形,否則會失敗
  }
};

export default REDUX_PERSIST;
RehydrationServices.ts 判斷是否替換持久化數(shù)據(jù)文件
import { AsyncStorage } from 'react-native';
import { persistStore } from 'redux-persist';

import ReduxPersist from './ReduxPersist';

const updateReducers = (store: any) => {
  const reducerVersion = ReduxPersist.reducerVersion;
  const config = ReduxPersist.storeConfig;
  // 按照配置要求自動持久化reducer
  persistStore(store, config);

  AsyncStorage.getItem('reducerVersion').then((localVersion) => {
    // 從本地存儲取出reducer版本并比較
    if (localVersion !== reducerVersion) {
      // 如果本地存儲中的reducer版本與配置文件中的reducer版本不同,則需要清理持久化數(shù)據(jù)
      persistStore(store, config, () => {
        persistStore(store, config);
      }).purge();
      // 清理成功,將本地存儲中的reducer版本設為配置文件中的reducer版本
      AsyncStorage.setItem('reducerVersion', reducerVersion);
    }
  }).catch(() => AsyncStorage.setItem('reducerVersion', reducerVersion));
}

export default {updateReducers};
reducer/index.ts 合并所有reducers和導出黑名單
// 工具函數(shù),用于組織多個reducer,并返回reducer集合
import { combineReducers } from 'redux';

import configReducer from './configReducer';
import reduxPersister from './reduxPersister'
let reducers = {
    config:configReducer,
    reduxPersister,
};
// 導出所有reducer
export default combineReducers(reducers);
// 添加persist黑名單,以下這些reducer不需要持久化
export const persistentStoreBlacklist = [
    'config',
  ];
ImmutablePersistenceTransform.ts 數(shù)據(jù)合并和轉換文件
import R from 'ramda';
import Immutable from 'seamless-immutable';

// 將redux中的immutable對象轉為普通js對象,以便于持久化存儲
const isImmutable = R.has('asMutable');
const convertToJs = (state: any) => state.asMutable({deep: true});
const fromImmutable = R.when(isImmutable, convertToJs);

// 將普通js對象轉為immutable不可變,以供redux使用
const toImmutable = (raw: any) => Immutable(raw);

export default {
  out: (state: any) => {
    // 設置深度合并
    state.mergeDeep = R.identity;
    // 從倉庫中取出,進入內(nèi)存時,轉為immutable不可變
    return toImmutable(state);
  },
  in: (raw: any) => {
    // 進入倉庫時,將immutable不可變數(shù)據(jù)轉為常規(guī)數(shù)據(jù)
    return fromImmutable(raw);
  }
};
action.ts 異步action文件
import * as actionTypes from './actionTypes'
export function DemoAction(params:boolean) {
    return (dispatch:any, getState:any) => {
        dispatch({
            type: actionTypes.SOMETEST,
            data: params
        });
    };
};
configReducer.ts
import * as actionTypes from '../action/actionTypes';

const initialState = {
    someData: ''
};

export default (state = initialState, action:any) => {
    switch (action.type) {
        case actionTypes.SOMETEST:
            return {
                ...state,
                someData: action.data
            }
        
        default:
            return state
    }
};

參考文章:

張京《在React Native中將Redux數(shù)據(jù)持久化》

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 本文使用的 Demo 完整代碼在這 react_native_complete_demo。 最開始接到公司通知要開...
    L小庸閱讀 7,982評論 8 67
  • 苑永志 特贊前端總監(jiān),技術愛好廣泛,做過Java,寫過頁面,正在搞Node.js。目前負責特贊前端團隊的人才培養(yǎng)...
    里奧的雜談閱讀 2,896評論 1 4
  • 當生命的枝頭繁華落盡,請為我唱一支平淡歸真的歌謠;當生命的枝頭梅紅傲雪,請為我折去不堪修剪的枝椏。透過人間草木吐納...
    無忌西東7閱讀 256評論 0 10
  • 周一,雨。周二,雨。周三,雨?!?周六,晴。周日,晴。 周一,雨。周二,雨。…… 周六,晴。周日,晴。 本地的天...
    再唱閱讀 304評論 0 0
  • 做人,不能缺德,缺錢可以賺,缺德準完蛋。不是別人看不破,只是看破不說破?;钪辛夹?,才是立身之本。 人活著別缺德,...
    戰(zhàn)狼觀察閱讀 1,111評論 0 0

友情鏈接更多精彩內(nèi)容