美文网首页
React-Native 数据持久化探索

React-Native 数据持久化探索

作者: 我叫傻先生 | 来源:发表于2019-04-19 11:18 被阅读0次
    • 使用RN也有一段时间了,但是却未试过在RN项目中实现数据的持久化,虽然项目继承了react-redux,但是数据存在于内存中,用户关闭APP后,需要重新初始化数据,网上大多RN数据持久化都是将一些数据存在AsyncStorage中,但是却打断了与redux的联系
    • Github上已经有现成的redux-persist包以解决redux持久化问题,但在实际使用过程中,还有很多问题需要解决。具体来说,redux-persist这个包提供的是通用解决方案,也可以用于react.js,如果你要用在react-native中的话,需要指定AsyncStorage,另外,虽然它还额外提供了两个transform插件redux-persist-transform-immutableredux-persist-immutable,但这两个插件目前使用起来还是有问题没有解决,为了尽快用上redux-persist,可以使用以下方案。
    解决

    在建立redux store时,除了常规会用到的各种中间件以外,我们需要额外引入redux-persist里的autoRehydrate增强器,然后启动持久化。

    Store.ts
    import { applyMiddleware, createStore, compose } from 'redux';
    import { autoRehydrate } from 'redux-persist';
    import createSagaMiddleware from 'redux-saga';
    // 中间件,作用:如果不使用该中间件,当我们dispatch一个action时,需要给dispatch函数传入action对象;
    // 但如果我们使用了这个中间件,那么就可以传入一个函数,这个函数接收两个参数: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不可变的,此处必须将常规数据做变形,否则会失败
      }
    };
    
    export default REDUX_PERSIST;
    
    RehydrationServices.ts 判断是否替换持久化数据文件
    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版本不同,则需要清理持久化数据
          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和导出黑名单
    // 工具函数,用于组织多个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 数据合并和转换文件
    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;
        // 从仓库中取出,进入内存时,转为immutable不可变
        return toImmutable(state);
      },
      in: (raw: any) => {
        // 进入仓库时,将immutable不可变数据转为常规数据
        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数据持久化》

    相关文章

      网友评论

          本文标题:React-Native 数据持久化探索

          本文链接:https://www.haomeiwen.com/subject/iocqgqtx.html