2 years ago

#72639

test-img

Fernando Tiburcio

How can I add new property on redux initial state and get successfuly merged of initial state and local persisted state using redux-persist

I'm having problems trying to add a new property to my redux store, on @@INIT and PERSIST of redux-persist steps all seems to be good but on the REHYDRATE step the redux-persist does not merge my local persisted store with my initial_state, persist just drop my new property and only recover my persisted local store.


Here is my store :

import Constants from 'expo-constants';
import * as Sentry from '@sentry/react';
import { toastReducer as toast } from 'react-native-redux-toast';
import {
  applyMiddleware, combineReducers, compose, createStore,
} from 'redux';
import { resettableReducer } from 'reduxsauce';
import { composeWithDevTools } from 'redux-devtools-extension';
import {
  consumeActionMiddleware,
  offlineMiddleware as libOfflineMiddleware,
  reducer as offlineReducer,
  suspendSaga,
} from 'redux-offline-queue';
import { createTransform, persistReducer, persistStore } from 'redux-persist';
import createSagaMiddleware from 'redux-saga';

import { configPersist } from '@agriness-mobile/arca-business/dist/store';

import { convertStringToUtcMoment, stringifyDateTime } from '~/helpers';
import { RESET_STORE_LOCAL, RESET_STORE_MIRROR } from '~/constants';
import {
  AuthReducers, DownloadStatusReducers, LocalReducers, MirrorReducers,
} from '~/reducers';

import {
  AuthLifecycleMiddleware,
  FilterUnusedActionsMiddleware,
  LoginGateKeeperMiddleware,
} from './middlewares';
import rootSaga from './Sagas';

const createDateTransform = (config) => createTransform(
  stringifyDateTime,
  convertStringToUtcMoment,
  config,
);

const migrations = {};
const configStore = (callback = null, reduxSagasErrorHandler = null) => {
  const { releaseChannel } = Constants.manifest;

  /*
    Sentry https://docs.sentry.io/platforms/javascript/guides/react/configuration/integrations/redux/
  */

  const optionsSentryRedux = {
    stateTransformer: !releaseChannel
      ? (_) => _
      : (state) => {
        const { _persist: persistLocal, ...local } = state.local;
        const { _persist: persistDownloadStatus, ...downloadStatus } = state.downloadStatus;
        return {
          downloadStatus,
          farms: state.mirror.farms,
          local,
          username: state.auth?.username,
        };
      },
  };

  const sentryReduxEnhancer = Sentry.createReduxEnhancer(optionsSentryRedux);

  /*
    Add LoginReducer persistence configs (using expo-secure-store lib) with a transform for
    accessTokenExpirationDate (String -> Date).
  */

  const sagaMiddleware = createSagaMiddleware({ onError: reduxSagasErrorHandler });

  const middlewares = [];
  middlewares.push(libOfflineMiddleware());
  middlewares.push(suspendSaga(sagaMiddleware));
  middlewares.push(FilterUnusedActionsMiddleware);
  middlewares.push(LoginGateKeeperMiddleware);
  middlewares.push(AuthLifecycleMiddleware);
  middlewares.push(consumeActionMiddleware());

  const resettableLocal = resettableReducer(RESET_STORE_LOCAL);
  const resettableMirror = resettableReducer(RESET_STORE_MIRROR);

  const appReducers = combineReducers({
    auth: persistReducer(configPersist.authPersistConfig, AuthReducers),
    downloadStatus: persistReducer(
      configPersist.downloadStatusPersistConfig,
      resettableMirror(DownloadStatusReducers),
    ),
    local: resettableLocal(LocalReducers),
    mirror: persistReducer(configPersist.mirrorPersistConfig, resettableMirror(MirrorReducers)),
    offline: persistReducer(configPersist.offlinePersistConfig, resettableLocal(offlineReducer)),
    toast,
  });

  const middlewaresApplied = applyMiddleware(...middlewares);

  let enhancers;

  if (!releaseChannel) {
    const reduxDevToolsOptions = {};
    enhancers = composeWithDevTools(reduxDevToolsOptions)(middlewaresApplied);
  } else {
    enhancers = middlewaresApplied;
  }

  const persistedReducer = persistReducer(configPersist.persistConfigSecondLevel(migrations), appReducers);

  const store = createStore(persistedReducer, compose(enhancers, sentryReduxEnhancer));
  const persistor = persistStore(store, null, callback);

  sagaMiddleware.run(rootSaga, persistor);

  return { persistor, store };
};

export default { configStore, createDateTransform };

here is my reducer :

import { createReducer } from 'reduxsauce';

import FarmHandlers from './Farm/Mirror';
import RecommendationsHandlers from './Recommendations/Mirror';

export const INITIAL_STATE = {
  currentRecommendationEvidence: [],
  farms: [],
};

const HANDLERS = {
  ...FarmHandlers,
  ...RecommendationsHandlers,
};

export default createReducer(INITIAL_STATE, HANDLERS);

and here is my configPersist :

import Constants from 'expo-constants';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createMigrate, createTransform } from 'redux-persist';

import { convertStringToUtcMoment, stringifyDateTime } from '~/helpers';

const createDateTransform = config => createTransform(stringifyDateTime, convertStringToUtcMoment, config);

const { releaseChannel } = Constants.manifest;

const persistConfigSecondLevel = migrations => ({
  blacklist: ['offline', 'auth'],
  debug: !releaseChannel,
  key: 'root',
  migrate: createMigrate(migrations, { debug: !releaseChannel }),
  storage: AsyncStorage,
  timeout: 0,
  version: 2,
  whitelist: ['mirror', 'local', 'notifications'],
});

const downloadStatusPersistConfig = {
  key: 'downloadStatus',
  storage: AsyncStorage,
  timeout: 0,
};

const mirrorPersistConfig = {
  key: 'mirror',
  storage: AsyncStorage,
  timeout: 0,
  whitelist: ['farms'],
};

const authPersistConfig = {
  blacklist: ['authRequestLoading', 'failureMessage'],
  key: 'auth',
  storage: AsyncStorage,
  timeout: 0,
  transforms: [createDateTransform({ whitelist: ['accessTokenExpirationDate', 'refreshTokenExpirationDate'] })],
};

const notificationsPersistConfig = {
  key: 'notifications',
  storage: AsyncStorage,
  timeout: 0,
};

const offlinePersistConfig = {
  blacklist: ['isConnected'],
  key: 'offline',
  storage: AsyncStorage,
  timeout: 0,
};

export {
  authPersistConfig,
  downloadStatusPersistConfig,
  mirrorPersistConfig,
  notificationsPersistConfig,
  offlinePersistConfig,
  persistConfigSecondLevel,
};

I've already tried to use autoMergeLevel1 or 2 on mirrorPersistConfig with stateReconciler prop but I was not successful.

react-native

redux

local-storage

redux-persist

0 Answers

Your Answer

Accepted video resources