I am working on a React Native (react@~16.9.0
) Expo (expo@~37.0.3
) Android app that is supposed to store hour registration data locally, for this redux-persist@^6.0.0
is used.
I created a RegistrationWeek
domain object that contains all data and some helper functions:
import moment, { Moment } from "moment";import { ..., addRegistrationWeek, updateRegistrationWeek } from '../store/register';export class RegistrationDay { ... constructor(...) { ... }}export default class RegistrationWeek { ... constructor(...) { ... } totalTime() { ... } dateRange() { ... } ... static init(store?) { if(store) { RegistrationWeek.store = store }; const register = RegistrationWeek.store.getState().register; ... } static async save(week: RegistrationWeek): Promise<any> { return new Promise((resolve) => { const register = RegistrationWeek.store.getState().register; const existing = register.registrationData.findIndex(w => w.startDate === week.startDate); if (existing >= 0) { updateRegistrationWeek(RegistrationWeek.store, week); } else { addRegistrationWeek(RegistrationWeek.store, week); } return resolve(week); }); } ...}
The register.ts
file that has the registrationReducer
in it looks as follows:
import RegistrationWeek from "../models/RegistrationWeek";...export function addRegistrationWeek(store, week: RegistrationWeek) { const action: { type: string, week: RegistrationWeek, } = { type: 'ADD_REGISTRATION_WEEK', week, } store.dispatch(action);}export function updateRegistrationWeek(store, week: RegistrationWeek) { const action: { type: string, week: RegistrationWeek, } = { type: 'UPDATE_REGISTRATION_WEEK', week, } store.dispatch(action);}...// Initial Stateconst initialState : { registrationData: RegistrationWeek[], ...} = { registrationData: [], ...};// Reducers (Modifies The State And Returns A New State)const registrationReducer = (state = initialState, action) => { switch (action.type) { ... case 'ADD_REGISTRATION_WEEK': { return { ...state, registrationData: [ ...state.registrationData, action.week, ], }; } case 'UPDATE_REGISTRATION_WEEK': { const updatedArray: RegistrationWeek[] = [...state.registrationData]; const index = updatedArray.findIndex((w: RegistrationWeek) => w.startDate === action.week.startDate); updatedArray[index] = action.week; return { ...state, registrationData: updatedArray, }; } default: { return state; } }};export default registrationReducer;
This registrationReducer
is configured and included in a rootReducer
along with a Transformer
:
// Imports: Dependenciesimport { combineReducers } from 'redux';// Imports: Reducersimport registerReducer from './register';import { persistReducer } from 'redux-persist';import { AsyncStorage } from 'react-native';import Transformer from './transformer';const registerPersistConfig = { key: 'register', storage: AsyncStorage, transformers: [Transformer], whitelist: ['registrationData', ...], blacklist: [],};// Redux: Root Reducerconst rootReducer = combineReducers({ register: persistReducer(registerPersistConfig, registerReducer),});export default rootReducer;
The Transformer
looks as follows:
import { createTransform, TransformInbound, TransformOutbound } from 'redux-persist';import RegistrationWeek, { RegistrationDay } from '../models/RegistrationWeek';interface State { registrationData: RegistrationWeek[], ...}const Transformer = createTransform<State, State, any, any>( // transform state on its way to being serialized and persisted. (inboundState: State, key) => { return { ...inboundState }; }, // transform state being rehydrated (outboundState: State, key) => { return { registrationData: outboundState.registrationData.map((w: RegistrationWeek) => { new RegistrationWeek(..., w.days.map((d: RegistrationDay) => { return new RegistrationDay(...) }))}), ...outboundState, } }, { whitelist: ['registrationData'] });export default Transformer;
Neither of the transformation methods seems to be called since putting console.log(...)
statements in them does not result in any output in the console.
The store
instance is configured here:
import { createStore } from 'redux';import { persistStore, persistReducer } from 'redux-persist';import { AsyncStorage } from 'react-native'import rootReducer from './index';const persistConfig = { key: 'root', storage: AsyncStorage, whitelist: ['register'], blacklist: [],};// Middleware: Redux Persist Persisted Reducerconst persistedReducer = persistReducer(persistConfig, rootReducer);// Redux: Storeconst store = createStore(persistedReducer);// Middleware: Redux Persist Persisterlet persistor = persistStore(store);const getPersistor = () => persistor;const getStore = () => store;const getState = () => { return store.getState();};export { getStore, getState, getPersistor};export default { getStore, getState, getPersistor}
Whenever persisted data gets retrieved after launching the app, it looks like:
Array [ Object {"days": Array [ Object { ... }, ... ], ... },]
Instead of the way it looks when saving the data:
Array [ RegistrationWeek {"days": Array [ RegistrationDay { ... }, ... ], ... },]
I am relying on the totalTime()
and dateRange()
methods from the RegistrationWeek
object in my UI but after rehydration it does not work anymore because the objects aren't instantiated properly.Doing this as part of a component render function does work, but the downside with that is that there would be an even bigger mix of templating and data manipulation. The loops would also be repeated every time the component is rendered, which seems like an uneccesarry performance impact to me.I hoped the strong typing, the transformer and the configuration would do the trick but somehow it does not seem to be called even though state is persisted.
If anyone has any tips, things I missed, on how to deal with this, please let me know!