Open vidhyeshpatil opened 4 years ago
Hi @vidhyeshpatil!
You need to create a migration and pass it to your persistConfig
.
Here is an example:
import rootReducer from './reducers';
const migrations = {
0: (state) => {
return {
...state,
settings: {
...state.settings,
moodColorCategory: {
colorPalette: 'DEFAULT',
}
}
}
},
};
const persistConfig = {
key: 'root',
storage: AsyncStorage,
version: 0,
timeout: 0,
migrate: createMigrate(migrations, { debug: true }),
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
export default () => {
const store = createStore(persistedReducer, {}, applyMiddleware(ReduxThunk));;
const persistor = persistStore(store);
return { store, persistor };
}
As you can see I created a migrations
object and gave it the key 0
which I then matched to the version
in persistConfig
.
When your app runs again it will check for the key 0 and return the state
that is returned by the key 0
in migrations
. In other words: whatever you return from 0
is your new state. In your case it would be something like:
const migrations = {
0: (state) => {
return {
...state,
reducerA: {
...state.reducerA, // number: 0
checkPage: [],
}
}
},
};
In the future, you would increment this number by one and on app start redux persist will check if its bigger than the current version and if it is it will migrate the new state.
This is currently my migrations
object (so you get the idea):
import moment from 'moment';
import strings from './i18n/strings';
import ReduxThunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';
import AsyncStorage from '@react-native-community/async-storage';
import { persistStore, persistReducer, createMigrate } from 'redux-persist';
import { defaultActivities, ADDED_IN_VERSION_3_4 } from './assets/activities/activities';
import { INITIAL_HOME_WIDGETS, INITIAL_MENU_ITEMS, LINE_CHART_CURVE_TYPES, TIME_WINDOWS } from './constants';
import { EXTENDED_EMOTIONS_MAP_AS_ARRAY, EXTENDED_EMOTIONS_MAP, ALL_EMOTIONS, BASIC_EMOTIONS } from './assets/objectProperties/emotionsMap';
import rootReducer from './reducers';
const migrations = {
0: (state) => {
return {
...state,
settings: {
...state.settings,
moodColorCategory: {
colorPalette: 'DEFAULT',
}
}
}
},
1: (state) => {
return {
...state,
settings: {
...state.settings,
layoutCategory: {
...state.settings.layoutCategory,
moodLayout: 'GRID',
firstMonthToShow: 1,
shouldHighlightCurrentDay: true,
},
moodSelectionCategory: {
defaultAndCustomMoodsAsSingleArray: EXTENDED_EMOTIONS_MAP_AS_ARRAY,
defaultAndCustomMoodsAsSegmentedObject: EXTENDED_EMOTIONS_MAP
}
}
}
},
2: (state) => {
return {
...state,
settings: {
...state.settings,
moodColorCategory: {
...state.settings.moodColorCategory,
shouldUseDefaultColorPalettes: true,
customMoodColors_1: null,
customMoodColors_2: null,
customMoodColors_3: null,
customMoodSelected: null,
},
languagePreference: {
userEnforcedLanguage: null,
},
whatsNew: {
showWhatsNewModal: true,
}
}
}
},
3: (state) => {
return {
...state,
settings: {
...state.settings,
backgroundCategory: {
isBackgroundUsingVideo: true,
savedImage: null,
savedVideo: 'defaultVideo',
},
whatsNew: {
showWhatsNewModal: true,
},
}
}
},
4: (state) => {
return {
...state,
challenges: [],
pastChallenges: [],
googleDrive: {
userInfo: null,
lastBackupTimestamp: null,
},
settings: {
...state.settings,
whatsNew: {
showWhatsNewModal: true,
},
}
}
},
5: (state) => {
return {
...state,
userInfo: {
...state.userInfo,
lastViewedRewardedVideo: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"),
},
settings: {
...state.settings,
whatsNew: {
showWhatsNewModal: true,
},
}
}
},
6: (state) => {
return {
...state,
activities: defaultActivities,
pinlock: {
pin: '',
pinlockEnabled: false,
},
settings: {
...state.settings,
whatsNew: {
showWhatsNewModal: true,
},
}
}
},
7: (state) => {
return {
...state,
settings: {
...state.settings,
layoutCategory: {
...state.settings.layoutCategory,
shouldAllowFloatingButton: true,
shouldAllowWhiteBorders: false,
shouldAllowGradients: true,
firstMonthToShow: 1,
},
whatsNew: {
showWhatsNewModal: true,
},
}
}
},
8: (state) => {
return {
...state,
settings: {
...state.settings,
layoutCategory: {
...state.settings.layoutCategory,
shouldAllowWhiteBorders: false,
shouldAllowGradients: true,
firstMonthToShow: 1,
shouldAllowActivities: true,
shouldAllowLocation: true,
},
whatsNew: {
showWhatsNewModal: true,
},
},
// open street maps
locationOSM: {
locationName: null,
openStreetMapId: null,
latitude: 85.287973,
longitude: 36.198180,
timestamp: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"),
},
// google maps
locationGM: {
cachedPredictions: [],
timestamp: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"),
},
// custom location
locationCL: {
cachedCustomLocations: [],
}
}
},
9: (state) => {
return {
...state,
settings: {
...state.settings,
backgroundCategory: {
...state.settings.backgroundCategory,
isBackgroundImageCustom: false,
},
whatsNew: {
showWhatsNewModal: true,
},
},
}
},
10: (state) => {
return {
...state,
settings: {
...state.settings,
layoutCategory: {
...state.settings.layoutCategory,
shouldAllowFloatingButton: true,
shouldAllowDotStyle: false,
dotStylePosition: 'right',
},
whatsNew: {
showWhatsNewModal: true,
},
migration: {
hasMigratedToMultipleEntries: false,
}
},
}
},
11: (state) => {
return {
...state,
extraNotifications: [],
settings: {
...state.settings,
layoutCategory: {
...state.settings.layoutCategory,
shouldAllowFloatingEntryButton: true,
},
ratingDescribers: {
happyMood: strings.EmotionsLayoutDescribers.basicMoods.happyMood,
contentMood: strings.EmotionsLayoutDescribers.basicMoods.contentMood,
neutralMood: strings.EmotionsLayoutDescribers.basicMoods.neutralMood,
sadMood: strings.EmotionsLayoutDescribers.basicMoods.sadMood,
depressedMood: strings.EmotionsLayoutDescribers.basicMoods.depressedMood,
},
whatsNew: {
showWhatsNewModal: true,
},
},
}
},
12: (state) => {
return {
...state,
settings: {
...state.settings,
layoutCategory: {
...state.settings.layoutCategory,
weekStartsOnMonday: true,
},
whatsNew: {
showWhatsNewModal: true,
},
},
}
},
13: (state) => {
return {
...state,
inAppReviews: {
rating: null,
feedback: '',
timestamp: null,
},
firebaseBackup: {
lastBackupTimestamp: null,
},
imageBackupTracker: {
toUpload: {},
toDelete: [],
},
userInfo: {
...state.userInfo,
birthday: null,
},
settings: {
...state.settings,
layoutCategory: {
...state.settings.layoutCategory,
shouldAllowPhotos: true,
shouldAllowCalendarFullWidth: false,
googleColorScheme: 'Standard',
},
notificationCategory: {
...state.settings.notificationCategory,
reminderNotifMinute: 0,
},
whatsNew: {
showWhatsNewModal: true,
},
tipsAndTricks: {
hasSeenPhotosMessage: false,
},
},
map: {
initialRegion: null,
},
autoSaveEntry: {
entryText: '',
timestamp: new Date().getTime(),
},
routines: {
activeRoutines: [],
routineProgress: {},
deletedRoutines: [],
customRoutineItems: [],
},
subscriptions: {
purchases: {},
lastValidationCheck: null,
isSubscriptionActive: false,
latestPurchasedProduct: null,
},
activities: [
...state.activities,
...ADDED_IN_VERSION_3_4,
]
}
},
14: (state) => {
return {
...state,
settings: {
...state.settings,
weather: {
allowWeather: true,
unitOfMeasurement: 'metric', // us_custom
},
tipsAndTricks: {
...state.settings.tipsAndTricks,
hasSeenMultipleEntriesMessage: false,
}
},
}
},
15: (state) => {
return {
...state,
settings: {
...state.settings,
tipsAndTricks: {
...state.settings.tipsAndTricks,
hasSeenMonthStatisticMessage: false,
},
hapticFeedback: {
allowHapticFeedback: false,
},
},
}
},
16: (state) => {
return {
...state,
settings: {
...state.settings,
layoutCategory: {
...state.settings.layoutCategory,
currentActiveJournalTab: 'entry',
backgroundOpacity: .72,
elementBackgroundColor: 100,
isShowingCurrentWeek: false,
monthView: 'default',
menuItems: [...INITIAL_MENU_ITEMS],
homeComponentWidgets: [...INITIAL_HOME_WIDGETS],
},
migration: {
...state.migration,
hasMigratedToAccurateTimestamps: false,
},
insightCategory: {
ratingLineChartCurve: LINE_CHART_CURVE_TYPES[0], // step or average
timeWindowToDisplay: TIME_WINDOWS[0],
},
},
notifications: {},
gratitudeJournal: {},
quotes: {
todaysQuote: {
...strings.Quotes[0],
dateSet: new Date().getTime(),
},
likedQuotes: [],
},
emotions: {
allEmotions: [...ALL_EMOTIONS],
basicEmotions: [...BASIC_EMOTIONS],
},
};
}
};
const persistConfig = {
key: 'root',
storage: AsyncStorage,
version: 16,
timeout: 0,
migrate: createMigrate(migrations, { debug: true }),
writeFailHandler: error => console.log('ERROR PERSISTING DATA', error),
};
const persistedReducer = persistReducer(persistConfig, rootReducer);
export default () => {
const store = createStore(persistedReducer, {}, applyMiddleware(ReduxThunk));;
const persistor = persistStore(store);
return { store, persistor };
}
Hi @vidhyeshpatil!
You need to create a migration and pass it to your
persistConfig
.Here is an example:
import rootReducer from './reducers'; const migrations = { 0: (state) => { return { ...state, settings: { ...state.settings, moodColorCategory: { colorPalette: 'DEFAULT', } } } }, }; const persistConfig = { key: 'root', storage: AsyncStorage, version: 0, timeout: 0, migrate: createMigrate(migrations, { debug: true }), }; const persistedReducer = persistReducer(persistConfig, rootReducer); export default () => { const store = createStore(persistedReducer, {}, applyMiddleware(ReduxThunk));; const persistor = persistStore(store); return { store, persistor }; }
As you can see I created a
migrations
object and gave it the key0
which I then matched to theversion
inpersistConfig
.When your app runs again it will check for the key 0 and return the
state
that is returned by the key0
inmigrations
. In other words: whatever you return from0
is your new state. In your case it would be something like:const migrations = { 0: (state) => { return { ...state, reducerA: { ...state.reducerA, // number: 0 checkPage: [], } } }, };
In the future, you would increment this number by one and on app start redux persist will check if its bigger than the current version and if it is it will migrate the new state.
This is currently my
migrations
object (so you get the idea):import moment from 'moment'; import strings from './i18n/strings'; import ReduxThunk from 'redux-thunk'; import { createStore, applyMiddleware } from 'redux'; import AsyncStorage from '@react-native-community/async-storage'; import { persistStore, persistReducer, createMigrate } from 'redux-persist'; import { defaultActivities, ADDED_IN_VERSION_3_4 } from './assets/activities/activities'; import { INITIAL_HOME_WIDGETS, INITIAL_MENU_ITEMS, LINE_CHART_CURVE_TYPES, TIME_WINDOWS } from './constants'; import { EXTENDED_EMOTIONS_MAP_AS_ARRAY, EXTENDED_EMOTIONS_MAP, ALL_EMOTIONS, BASIC_EMOTIONS } from './assets/objectProperties/emotionsMap'; import rootReducer from './reducers'; const migrations = { 0: (state) => { return { ...state, settings: { ...state.settings, moodColorCategory: { colorPalette: 'DEFAULT', } } } }, 1: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, moodLayout: 'GRID', firstMonthToShow: 1, shouldHighlightCurrentDay: true, }, moodSelectionCategory: { defaultAndCustomMoodsAsSingleArray: EXTENDED_EMOTIONS_MAP_AS_ARRAY, defaultAndCustomMoodsAsSegmentedObject: EXTENDED_EMOTIONS_MAP } } } }, 2: (state) => { return { ...state, settings: { ...state.settings, moodColorCategory: { ...state.settings.moodColorCategory, shouldUseDefaultColorPalettes: true, customMoodColors_1: null, customMoodColors_2: null, customMoodColors_3: null, customMoodSelected: null, }, languagePreference: { userEnforcedLanguage: null, }, whatsNew: { showWhatsNewModal: true, } } } }, 3: (state) => { return { ...state, settings: { ...state.settings, backgroundCategory: { isBackgroundUsingVideo: true, savedImage: null, savedVideo: 'defaultVideo', }, whatsNew: { showWhatsNewModal: true, }, } } }, 4: (state) => { return { ...state, challenges: [], pastChallenges: [], googleDrive: { userInfo: null, lastBackupTimestamp: null, }, settings: { ...state.settings, whatsNew: { showWhatsNewModal: true, }, } } }, 5: (state) => { return { ...state, userInfo: { ...state.userInfo, lastViewedRewardedVideo: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"), }, settings: { ...state.settings, whatsNew: { showWhatsNewModal: true, }, } } }, 6: (state) => { return { ...state, activities: defaultActivities, pinlock: { pin: '', pinlockEnabled: false, }, settings: { ...state.settings, whatsNew: { showWhatsNewModal: true, }, } } }, 7: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowFloatingButton: true, shouldAllowWhiteBorders: false, shouldAllowGradients: true, firstMonthToShow: 1, }, whatsNew: { showWhatsNewModal: true, }, } } }, 8: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowWhiteBorders: false, shouldAllowGradients: true, firstMonthToShow: 1, shouldAllowActivities: true, shouldAllowLocation: true, }, whatsNew: { showWhatsNewModal: true, }, }, // open street maps locationOSM: { locationName: null, openStreetMapId: null, latitude: 85.287973, longitude: 36.198180, timestamp: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"), }, // google maps locationGM: { cachedPredictions: [], timestamp: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"), }, // custom location locationCL: { cachedCustomLocations: [], } } }, 9: (state) => { return { ...state, settings: { ...state.settings, backgroundCategory: { ...state.settings.backgroundCategory, isBackgroundImageCustom: false, }, whatsNew: { showWhatsNewModal: true, }, }, } }, 10: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowFloatingButton: true, shouldAllowDotStyle: false, dotStylePosition: 'right', }, whatsNew: { showWhatsNewModal: true, }, migration: { hasMigratedToMultipleEntries: false, } }, } }, 11: (state) => { return { ...state, extraNotifications: [], settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowFloatingEntryButton: true, }, ratingDescribers: { happyMood: strings.EmotionsLayoutDescribers.basicMoods.happyMood, contentMood: strings.EmotionsLayoutDescribers.basicMoods.contentMood, neutralMood: strings.EmotionsLayoutDescribers.basicMoods.neutralMood, sadMood: strings.EmotionsLayoutDescribers.basicMoods.sadMood, depressedMood: strings.EmotionsLayoutDescribers.basicMoods.depressedMood, }, whatsNew: { showWhatsNewModal: true, }, }, } }, 12: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, weekStartsOnMonday: true, }, whatsNew: { showWhatsNewModal: true, }, }, } }, 13: (state) => { return { ...state, inAppReviews: { rating: null, feedback: '', timestamp: null, }, firebaseBackup: { lastBackupTimestamp: null, }, imageBackupTracker: { toUpload: {}, toDelete: [], }, userInfo: { ...state.userInfo, birthday: null, }, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowPhotos: true, shouldAllowCalendarFullWidth: false, googleColorScheme: 'Standard', }, notificationCategory: { ...state.settings.notificationCategory, reminderNotifMinute: 0, }, whatsNew: { showWhatsNewModal: true, }, tipsAndTricks: { hasSeenPhotosMessage: false, }, }, map: { initialRegion: null, }, autoSaveEntry: { entryText: '', timestamp: new Date().getTime(), }, routines: { activeRoutines: [], routineProgress: {}, deletedRoutines: [], customRoutineItems: [], }, subscriptions: { purchases: {}, lastValidationCheck: null, isSubscriptionActive: false, latestPurchasedProduct: null, }, activities: [ ...state.activities, ...ADDED_IN_VERSION_3_4, ] } }, 14: (state) => { return { ...state, settings: { ...state.settings, weather: { allowWeather: true, unitOfMeasurement: 'metric', // us_custom }, tipsAndTricks: { ...state.settings.tipsAndTricks, hasSeenMultipleEntriesMessage: false, } }, } }, 15: (state) => { return { ...state, settings: { ...state.settings, tipsAndTricks: { ...state.settings.tipsAndTricks, hasSeenMonthStatisticMessage: false, }, hapticFeedback: { allowHapticFeedback: false, }, }, } }, 16: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, currentActiveJournalTab: 'entry', backgroundOpacity: .72, elementBackgroundColor: 100, isShowingCurrentWeek: false, monthView: 'default', menuItems: [...INITIAL_MENU_ITEMS], homeComponentWidgets: [...INITIAL_HOME_WIDGETS], }, migration: { ...state.migration, hasMigratedToAccurateTimestamps: false, }, insightCategory: { ratingLineChartCurve: LINE_CHART_CURVE_TYPES[0], // step or average timeWindowToDisplay: TIME_WINDOWS[0], }, }, notifications: {}, gratitudeJournal: {}, quotes: { todaysQuote: { ...strings.Quotes[0], dateSet: new Date().getTime(), }, likedQuotes: [], }, emotions: { allEmotions: [...ALL_EMOTIONS], basicEmotions: [...BASIC_EMOTIONS], }, }; } }; const persistConfig = { key: 'root', storage: AsyncStorage, version: 16, timeout: 0, migrate: createMigrate(migrations, { debug: true }), writeFailHandler: error => console.log('ERROR PERSISTING DATA', error), }; const persistedReducer = persistReducer(persistConfig, rootReducer); export default () => { const store = createStore(persistedReducer, {}, applyMiddleware(ReduxThunk));; const persistor = persistStore(store); return { store, persistor }; }
Thanks for your detailed description, appreciated.
But maintaining lot of version in future, would be a one more hectic step. Also as per your code example shared by you setting a timeout 0 the application doesn't start it just displays my loader, the state doesn't get rehydrated.
Setting mirgrations object, it doesn't reflect when I am tried to implement & run the application local. It doesn't updates the new additional value.
Any better alternative, which we can do to achieve this scenario, because if I want to add new additional reducer that time also it will result an issue.
Hmm migrations from redux-persist are def the way to go. I would encourage you to stick to this method. All the best!
Simple answer is: remove/clear storage manually and then refresh page, it will add your updated key value pair
La respuesta simple es: elimine / borre el almacenamiento manualmente y luego actualice la página, agregará su par de valor clave actualizado
How would I do if my project is in production? it's a bit annoying to ask the user to clean up their local storage
Simple answer is:
export const migrations = {
16: () => ({}),
};
I tried this solution from the official documentation https://github.com/rt2zz/redux-persist/blob/master/docs/migrations.md#alternative and it worked without manually updating the persistConfig
version every time.
@unigazer : Can you describe solution in little more details? Instead or writing migrations like @wmonecke did, we just have to write this code?
migrate: (state) => { console.log('Migration Running!') return Promise.resolve(state) }
I didn't understand whats given on that link :/
Yes @amitpatil321 I just tested it and it woks for me
Tôi đã thử giải pháp này từ tài liệu chính thức https://github.com/rt2zz/redux-persist/blob/master/docs/migrations.md#alternative và nó hoạt động mà không cần cập nhật
persistConfig
phiên bản theo cách thủ công mỗi lần.
I used this method fine, but now it's not working
Migration can be a way. But I created a function to check the number of keys in reducer with a hard coded value. If they are not equal logout and clear the persisted state in local storage and also do not render the children. You can run this in useEffect hook. This function needs to run at the top level of application (index.js or app.js in react) .
useEffect(() => {
const NO_OF_REDUX_STATE_KEYS = 1
//1) if we add new properties in redux it won't be avalaible in the already loggedin user's redux-persist state, so user needs to login again to maintain the state.
if (Object.keys(reduxState).length !== NO_OF_REDUX_STATE_KEYS) {
setShowChildren(false)
localStorage.removeItem('persist:Hoichoi')
router.push('/') // login page
} else {
setShowChildren(true)
}
}
Hi @vidhyeshpatil!
You need to create a migration and pass it to your
persistConfig
.Here is an example:
import rootReducer from './reducers'; const migrations = { 0: (state) => { return { ...state, settings: { ...state.settings, moodColorCategory: { colorPalette: 'DEFAULT', } } } }, }; const persistConfig = { key: 'root', storage: AsyncStorage, version: 0, timeout: 0, migrate: createMigrate(migrations, { debug: true }), }; const persistedReducer = persistReducer(persistConfig, rootReducer); export default () => { const store = createStore(persistedReducer, {}, applyMiddleware(ReduxThunk));; const persistor = persistStore(store); return { store, persistor }; }
As you can see I created a
migrations
object and gave it the key0
which I then matched to theversion
inpersistConfig
.When your app runs again it will check for the key 0 and return the
state
that is returned by the key0
inmigrations
. In other words: whatever you return from0
is your new state. In your case it would be something like:const migrations = { 0: (state) => { return { ...state, reducerA: { ...state.reducerA, // number: 0 checkPage: [], } } }, };
In the future, you would increment this number by one and on app start redux persist will check if its bigger than the current version and if it is it will migrate the new state.
This is currently my
migrations
object (so you get the idea):import moment from 'moment'; import strings from './i18n/strings'; import ReduxThunk from 'redux-thunk'; import { createStore, applyMiddleware } from 'redux'; import AsyncStorage from '@react-native-community/async-storage'; import { persistStore, persistReducer, createMigrate } from 'redux-persist'; import { defaultActivities, ADDED_IN_VERSION_3_4 } from './assets/activities/activities'; import { INITIAL_HOME_WIDGETS, INITIAL_MENU_ITEMS, LINE_CHART_CURVE_TYPES, TIME_WINDOWS } from './constants'; import { EXTENDED_EMOTIONS_MAP_AS_ARRAY, EXTENDED_EMOTIONS_MAP, ALL_EMOTIONS, BASIC_EMOTIONS } from './assets/objectProperties/emotionsMap'; import rootReducer from './reducers'; const migrations = { 0: (state) => { return { ...state, settings: { ...state.settings, moodColorCategory: { colorPalette: 'DEFAULT', } } } }, 1: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, moodLayout: 'GRID', firstMonthToShow: 1, shouldHighlightCurrentDay: true, }, moodSelectionCategory: { defaultAndCustomMoodsAsSingleArray: EXTENDED_EMOTIONS_MAP_AS_ARRAY, defaultAndCustomMoodsAsSegmentedObject: EXTENDED_EMOTIONS_MAP } } } }, 2: (state) => { return { ...state, settings: { ...state.settings, moodColorCategory: { ...state.settings.moodColorCategory, shouldUseDefaultColorPalettes: true, customMoodColors_1: null, customMoodColors_2: null, customMoodColors_3: null, customMoodSelected: null, }, languagePreference: { userEnforcedLanguage: null, }, whatsNew: { showWhatsNewModal: true, } } } }, 3: (state) => { return { ...state, settings: { ...state.settings, backgroundCategory: { isBackgroundUsingVideo: true, savedImage: null, savedVideo: 'defaultVideo', }, whatsNew: { showWhatsNewModal: true, }, } } }, 4: (state) => { return { ...state, challenges: [], pastChallenges: [], googleDrive: { userInfo: null, lastBackupTimestamp: null, }, settings: { ...state.settings, whatsNew: { showWhatsNewModal: true, }, } } }, 5: (state) => { return { ...state, userInfo: { ...state.userInfo, lastViewedRewardedVideo: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"), }, settings: { ...state.settings, whatsNew: { showWhatsNewModal: true, }, } } }, 6: (state) => { return { ...state, activities: defaultActivities, pinlock: { pin: '', pinlockEnabled: false, }, settings: { ...state.settings, whatsNew: { showWhatsNewModal: true, }, } } }, 7: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowFloatingButton: true, shouldAllowWhiteBorders: false, shouldAllowGradients: true, firstMonthToShow: 1, }, whatsNew: { showWhatsNewModal: true, }, } } }, 8: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowWhiteBorders: false, shouldAllowGradients: true, firstMonthToShow: 1, shouldAllowActivities: true, shouldAllowLocation: true, }, whatsNew: { showWhatsNewModal: true, }, }, // open street maps locationOSM: { locationName: null, openStreetMapId: null, latitude: 85.287973, longitude: 36.198180, timestamp: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"), }, // google maps locationGM: { cachedPredictions: [], timestamp: moment("January 20 2019 05:06:07", "MMMM DD YYYY hh:mm:ss"), }, // custom location locationCL: { cachedCustomLocations: [], } } }, 9: (state) => { return { ...state, settings: { ...state.settings, backgroundCategory: { ...state.settings.backgroundCategory, isBackgroundImageCustom: false, }, whatsNew: { showWhatsNewModal: true, }, }, } }, 10: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowFloatingButton: true, shouldAllowDotStyle: false, dotStylePosition: 'right', }, whatsNew: { showWhatsNewModal: true, }, migration: { hasMigratedToMultipleEntries: false, } }, } }, 11: (state) => { return { ...state, extraNotifications: [], settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowFloatingEntryButton: true, }, ratingDescribers: { happyMood: strings.EmotionsLayoutDescribers.basicMoods.happyMood, contentMood: strings.EmotionsLayoutDescribers.basicMoods.contentMood, neutralMood: strings.EmotionsLayoutDescribers.basicMoods.neutralMood, sadMood: strings.EmotionsLayoutDescribers.basicMoods.sadMood, depressedMood: strings.EmotionsLayoutDescribers.basicMoods.depressedMood, }, whatsNew: { showWhatsNewModal: true, }, }, } }, 12: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, weekStartsOnMonday: true, }, whatsNew: { showWhatsNewModal: true, }, }, } }, 13: (state) => { return { ...state, inAppReviews: { rating: null, feedback: '', timestamp: null, }, firebaseBackup: { lastBackupTimestamp: null, }, imageBackupTracker: { toUpload: {}, toDelete: [], }, userInfo: { ...state.userInfo, birthday: null, }, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, shouldAllowPhotos: true, shouldAllowCalendarFullWidth: false, googleColorScheme: 'Standard', }, notificationCategory: { ...state.settings.notificationCategory, reminderNotifMinute: 0, }, whatsNew: { showWhatsNewModal: true, }, tipsAndTricks: { hasSeenPhotosMessage: false, }, }, map: { initialRegion: null, }, autoSaveEntry: { entryText: '', timestamp: new Date().getTime(), }, routines: { activeRoutines: [], routineProgress: {}, deletedRoutines: [], customRoutineItems: [], }, subscriptions: { purchases: {}, lastValidationCheck: null, isSubscriptionActive: false, latestPurchasedProduct: null, }, activities: [ ...state.activities, ...ADDED_IN_VERSION_3_4, ] } }, 14: (state) => { return { ...state, settings: { ...state.settings, weather: { allowWeather: true, unitOfMeasurement: 'metric', // us_custom }, tipsAndTricks: { ...state.settings.tipsAndTricks, hasSeenMultipleEntriesMessage: false, } }, } }, 15: (state) => { return { ...state, settings: { ...state.settings, tipsAndTricks: { ...state.settings.tipsAndTricks, hasSeenMonthStatisticMessage: false, }, hapticFeedback: { allowHapticFeedback: false, }, }, } }, 16: (state) => { return { ...state, settings: { ...state.settings, layoutCategory: { ...state.settings.layoutCategory, currentActiveJournalTab: 'entry', backgroundOpacity: .72, elementBackgroundColor: 100, isShowingCurrentWeek: false, monthView: 'default', menuItems: [...INITIAL_MENU_ITEMS], homeComponentWidgets: [...INITIAL_HOME_WIDGETS], }, migration: { ...state.migration, hasMigratedToAccurateTimestamps: false, }, insightCategory: { ratingLineChartCurve: LINE_CHART_CURVE_TYPES[0], // step or average timeWindowToDisplay: TIME_WINDOWS[0], }, }, notifications: {}, gratitudeJournal: {}, quotes: { todaysQuote: { ...strings.Quotes[0], dateSet: new Date().getTime(), }, likedQuotes: [], }, emotions: { allEmotions: [...ALL_EMOTIONS], basicEmotions: [...BASIC_EMOTIONS], }, }; } }; const persistConfig = { key: 'root', storage: AsyncStorage, version: 16, timeout: 0, migrate: createMigrate(migrations, { debug: true }), writeFailHandler: error => console.log('ERROR PERSISTING DATA', error), }; const persistedReducer = persistReducer(persistConfig, rootReducer); export default () => { const store = createStore(persistedReducer, {}, applyMiddleware(ReduxThunk));; const persistor = persistStore(store); return { store, persistor }; }
What should be the type of the state in TypeScript , RootState, right?
0: (state) => {
return {
...state,
reducerA: {
...state.reducerA, // number: 0
checkPage: [],
}
}
},
};
What is the best way to update persistStore when my store / reducer is updated with new key, value (inside initial state) or a new reducer.
The problem which I am facing write now, is my persistStore is not getting updated when I update my reducer with additional value.
eg: Reducer A Old one
const initialState = { number: 0 }
Updated one const initialState = { number: 0, checkPage: [] }
When my application runs again, it tries to access checkPage array it throws an error "Cannot read property undefined of undefined". Which means my persistedReducer was not updated.
A common use case, Can you suggest the best way to resolve the issue ?