Hi,
I'm currently working on a react-native app where data is always valid for 2 weeks. Therefore I use apollo-client and redux-persist to cache those data to the file system. Now I'm trying to register a background job with react-native-background-job to delete old data.
My store setup looks like this:
import ApolloClient, { createNetworkInterface } from 'apollo-client'
import { applyMiddleware, combineReducers, createStore } from 'redux'
import createSagaMiddleware from 'redux-saga'
import logger from 'redux-logger'
import rootReducer from '../reducers'
import { persistReducer, persistStore } from 'redux-persist'
import rootSaga from '../sagas/root'
import FSStorage, { CacheDir } from 'redux-persist-fs-storage'
import { composeWithDevTools } from 'remote-redux-devtools'
export default (initialState = {}) => {
const sagaMiddleware = createSagaMiddleware()
const client = new ApolloClient({
networkInterface: createNetworkInterface({
uri: 'https://804rljq7q.lp.gql.zone/graphql'
})
})
const apolloPersistConfig = {
key: 'apollo',
storage: FSStorage(CacheDir, 'MensaApp')
}
const enhancer = composeWithDevTools(
applyMiddleware(logger, sagaMiddleware, client.middleware())
)
const store = createStore(
combineReducers({
root: rootReducer,
apollo: persistReducer(apolloPersistConfig, client.reducer())
// apollo: client.reducer()
}),
initialState,
enhancer
)
const persistor = persistStore(store)
sagaMiddleware.run(rootSaga)
return { store, client, persistor }
}
In my Background Job I have to configure the store and then wait until rehydration somehow. This is the point where I'm stuck.
BackgroundJob.register({
jobKey: TIDY_UP_CACHE_JOB,
job: () => {
const { store, client, persistor } = configureStore()
// wait until rehydration, but how?
client.resetStore()
}
})
If you have any hint for me on how to register some kind of callback that gets executed after rehydration is done, that'll be awesome.
Cheers,
Martin
two entry points I can think of:
let persistor = persistStore(store, null, () => {
// this will be invoked after rehydration is complete
}
<PersistGate
onBeforeLift={this.doSomething}
When you setup your store you can do the following:
let rehydrationComplete
let rehydrationFailed
const rehydrationPromise = new Promise((resolve, reject) => {
rehydrationComplete = resolve
rehydrationFailed = reject
})
export function rehydration () {
return rehydrationPromise
}
export default (initialState = {}) => {
// ... setup middleware and all the other boiler plate
const persistor = persistStore(store)
sagaMiddleware.run(rootSaga)
rehydrationComplete() // if you detect that an error occurred during rehydration you can call rehydrationFailed
return { store, client, persistor }
}
You're exporting a function that returns a promise that resolves when the store is rehydrated.
You can then use it anywhere, incl. in background jobs, like this:
import {rehydration} from '...'
await rehydration() // this will continue when rehydration is complete. If the store is already rehydrated, it will continue immediately because the promise is already resolved. If rehydration failed, it will throw an exception
using @rt2zz's 1. method, I got an error:
TypeError: Cannot read property 'skipRestore' of null
// defaults
13 | // @TODO remove shouldRestore
> 14 | var shouldRestore = !config.skipRestore;
15 | if (process.env.NODE_ENV !== 'production' && config.skipRestore) console.warn('redux-persist: config.skipRestore has been deprecated. If you want to skip restoration use `createPersistor` instead');
16 |
17 | var purgeKeys = null;
Anyone has a clue what to put instead of null then?
I'm currently just doing the following in store.js:
const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = createStore(persistedReducer, composeEnhancers(applyMiddleware(thunk)));
export default (cb) => {
const persistor = persistStore(store, null, cb);
return { store, persistor };
};
But I run into an issue where the store in the background isn't persisted to the foreground...
One thing that seems to work to me is a combination of @daramasala and @rt2zz codes:
store.js
let rehydrationComplete;
let rehydrationFailed;
const rehydrationPromise = new Promise((resolve, reject) => {
rehydrationComplete = resolve;
rehydrationFailed = reject;
});
export function rehydration () {
return rehydrationPromise;
};
export default (initialState = {}) => {
// ... setup middleware and all the other boiler plate
const persistor = persistStore(store, null, () => {
// this will be invoked after rehydration is complete
rehydrationComplete();
});
return { store, client, persistor }
}
Then:
import { rehydration } from './store'
await rehydration();
How can I check by the time I am using store.getState(), the rehydration process has already been done? Because I am using store.getState() somewhere soon and it does not give me the persisted value. Instead, it gives me the default value that I specified in the reducer.
Most helpful comment
two entry points I can think of: