typescript - React Native Redux-Persist kallar inte transformern vid återhydrering


Jag arbetar med en React Native (react@~16.9.0) Expo (expo@~37.0.3) Android-app som ska lagra tidrapporteringsdata lokalt, för detta används redux-persist@^6.0.0.

Jag skapade ett RegistrationWeek-domänobjekt som innehåller all data och några hjälpfunktioner:

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);
    });
  }

  ...

}

Filen register.ts som innehåller registrationReducer ser ut som följer:

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 State
const 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;

Denna registrationReducer är konfigurerad och inkluderad i en rootReducer tillsammans med en Transformer:

// Imports: Dependencies
import { combineReducers } from 'redux';
// Imports: Reducers
import 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 Reducer
const rootReducer = combineReducers({
  register: persistReducer(registerPersistConfig, registerReducer),
});
export default rootReducer;

Transformern ser ut som följer:

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;

Inget av transformationsmetoderna verkar kallas eftersom att sätta console.log(...)-satser i dem inte resulterar i någon utskrift i konsolen.

Instansen store konfigureras här:

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 Reducer
const persistedReducer = persistReducer(persistConfig, rootReducer);
// Redux: Store
const store = createStore(persistedReducer);
// Middleware: Redux Persist Persister
let persistor = persistStore(store);

const getPersistor = () => persistor;
const getStore = () => store;
const getState = () => {
    return store.getState();
};export {
    getStore,
    getState,
    getPersistor
};export default {
    getStore,
    getState,
    getPersistor
}

Närsomhelst sparad data hämtas efter att appen startats ser det ut så här:

Array [
  Object {
    "days": Array [
      Object {
        ...
      },
      ...
    ],
    ...
  },
]

Istället för hur det ser ut när man sparar data:

Array [
  RegistrationWeek {
    "days": Array [
      RegistrationDay {
        ...
      },
      ...
    ],
    ...
  },
]

Jag förlitar mig på totalTime() och dateRange() metoderna från RegistrationWeek-objektet i mitt användargränssnitt, men efter rehydreringen fungerar det inte längre eftersom objekten inte instansieras korrekt. Att göra detta som en del av en komponentrenderingsfunktion fungerar dock, men nackdelen med det är att det skulle bli ännu en större blandning av mallar och datamanipulation. Looparna skulle också upprepas varje gång komponenten renderas, vilket verkar vara en onödig prestandapåverkan för mig. Jag hoppades att den starka typningen, transformern och konfigurationen skulle lösa problemet, men på något sätt verkar de inte kallas även om tillståndet bevaras.

Om någon har några tips, saker jag har missat, om hur man hanterar detta, vänligen låt mig veta!