Hey,
First off, thanks a bunch for this library, and also thanks a bunch for adding types.
I just installed this in an existing codebase and got a whole bunch of errors, starting with:
https://gist.github.com/deecewan/1924ac53d68129148fb56cb53d1d841f
That's a whole load of flow errors from the persistStore function.
Edit: this could maybe be fixed by changing this to:
const persistor = {
...createStore(...),
flush() {},
purge() {},
};
Happy to open a PR for that, if that'll fix things there. I'm running Flow v0.63 (I notice this lib is v0.59 at the moment - may be the source of issues).
Also, somewhat unrelated, but persistReducer makes my types go weird, because it returns State & { _persist: PersistState }, which doesn't match the type of my State. Is there a reason that this _persist item is stored in the user's state instead of the redux-persist redux store?
@rt2zz I think #697 will fix the majority of the flow errors, but still curious around why _persist is stored in the user's store rather than the store created with persistStore?
Doing this messes with my State type, because instead of being as expected, it's got an extra property on it, which I'm not too keen on adding manually because it looks like it's private.
@deecewan we might change this in v6 - but its definitely not a cut and dry issue from my perspective. Here is some context:
pros:
cons:
Con 4 is a big issue for me and I would definitely like to explore options for how we can resolve this. Perhaps storing _persist state in the persistor is the way to go, but then we have to worry about syncing it and persisting it.
While I am open to suggestion I think this is unlikely to change in the near future.
In the meantime I would recommend you add the _persist state to your State type. We export the PersistState shape so you can do something like
import { type PersistState } from 'redux-persist/src/types'
type State = {
//... your state shape
_persist: PersistState
}
@rt2zz thanks so much for the detailed response. I figured that you had probably looked at this, and was mostly just curious as to why this decision was made.
I'm interested to see what the eventual solution is, but for now I'm happy to go back to manually adding the key.
For anyone else who stumbles in here, I could not get my setup to play nicely with
import { type PersistState } from 'redux-persist/src/types'
type State = {
//... your state shape
_persist: PersistState
}
I got errors from some middleware, etc, and I didn't have time to diagnose.
I ended up just casting the persistReducer call and essentially ignoring the _persist key. I don't want that key used in the application itself, so this works out well.
My code looks like:
import type { State, Actions } from '../types/store';
const persistedReducer: (State, Actions) => State = persistReducer(config, reducer);
Now, flow is happy and I am happy.
I'm having similar problems and can not get it working. This is my store config:
const baseReducer: Reducer<StateType, StoreActionType> = combineReducers({
uiDirection: uiDirectionReducer,
language: languageReducer,
darkMode: toggleDarkModeReducer,
network: reactNativeOfflineReducer,
data: combineReducers({
cities: citiesReducer,
categories: categoriesReducer
})
})
const rootReducer: Reducer<PersistedStateType, StoreActionType> = persistReducer(persistConfig, baseReducer)
const middleware = applyMiddleware(createNetworkMiddleware(), sagaMiddleware, createLogger())
const store: Store<PersistedStateType, StoreActionType> = createStore(rootReducer, middleware)
The type of my store is:
export type StateType = {
uiDirection: string,
language: string,
darkMode: boolean,
network: { isConnected: boolean, actionQueue: Array<StoreActionType> },
data: {
cities: any,
categories: any
}
}
export type PersistedStateType = {
uiDirection: string,
language: string,
darkMode: boolean,
network: { isConnected: boolean, actionQueue: Array<StoreActionType> },
data: {
cities: any,
categories: any
},
_persist: PersistState
}
But I get the following error:
Error โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ src/modules/app/createReduxStore.js:91:69
Cannot assign persistReducer(...) to rootReducer because:
โข object type [1] is incompatible with undefined [2] in the first argument.
โข property darkMode is missing in PersistPartial [3] but exists in PersistedStateType [4] in the return value.
โข property data is missing in PersistPartial [3] but exists in PersistedStateType [4] in the return value.
โข property language is missing in PersistPartial [3] but exists in PersistedStateType [4] in the return value.
โข property network is missing in PersistPartial [3] but exists in PersistedStateType [4] in the return value.
โข property uiDirection is missing in PersistPartial [3] but exists in PersistedStateType [4] in the return value.
src/modules/app/createReduxStore.js
88โ })
89โ })
90โ
[4] 91โ const rootReducer: Reducer<PersistedStateType, StoreActionType> = persistReducer(persistConfig, baseReducer)
92โ
93โ const middleware = applyMiddleware(createNetworkMiddleware(), sagaMiddleware, createLogger())
94โ
flow-typed/npm/redux_v4.x.x.js
[2] 30โ declare export type Reducer<S, A> = (state: S | void, action: A) => S;
node_modules/redux-persist/lib/persistReducer.js.flow
[1] 30โ export default function persistReducer<State: Object, Action: Object>(
31โ config: PersistConfig,
32โ baseReducer: (State, Action) => State
[3] 33โ ): (State, Action) => State & PersistPartial {
The main problem is this:
Error โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ src/modules/app/createReduxStore.js:86:64
Cannot call createStore because StateType [1] is incompatible with undefined [2] in the first argument.
src/modules/app/createReduxStore.js
[1] 82โ const rootReducer: (state: StateType, action: StoreActionType) => StateType = baseReducer
83โ
84โ const middleware = applyMiddleware(createNetworkMiddleware(), sagaMiddleware, createLogger())
85โ
86โ const store: Store<StateType, StoreActionType> = createStore(rootReducer, {
87โ uiDirection: uiDirectionReducer,
88โ language: '',
89โ darkMode: false,
90โ network: {isConnected: false, actionQueue: []},
91โ data: {
92โ cities: {},
93โ categories: {}
94โ },
95โ _persist: {
96โ version: 0,
97โ rehydrated: false
98โ }
99โ }, middleware)
100โ
101โ sagaMiddleware.run(rootSaga)
102โ
flow-typed/npm/redux_v4.x.x.js
[2] 30โ declare export type Reducer<S, A> = (state: S | void, action: A) => S;
The redux Reducer type uses S | void as type for the state. But redux-persist uses an Object in the reducer definition.
I got it working by handling the void case separately:
const persistConfig = {
key: 'network',
storage: AsyncStorage
}
const initialState = {
uiDirection: uiDirectionReducer,
language: '',
darkMode: false,
network: {isConnected: false, actionQueue: []},
data: {
cities: {},
categories: {}
},
_persist: {
version: 0,
rehydrated: false
}
}
const baseReducer: (state: StateType | void, action: StoreActionType) => StateType = (state, action) => {
if (!state) {
return initialState
}
return persistCombineReducers(persistConfig, {
uiDirection: uiDirectionReducer,
language: languageReducer,
darkMode: toggleDarkModeReducer,
network: reactNativeOfflineReducer,
data: combineReducers({
cities: citiesReducer,
categories: categoriesReducer
})
})(state, action)
}
const middleware: StoreEnhancer<StateType, StoreActionType> = applyMiddleware(createNetworkMiddleware(), sagaMiddleware, createLogger())
const store: Store<StateType, StoreActionType> = createStore(baseReducer, initialState, middleware)
Most helpful comment
@rt2zz thanks so much for the detailed response. I figured that you had probably looked at this, and was mostly just curious as to why this decision was made.
I'm interested to see what the eventual solution is, but for now I'm happy to go back to manually adding the key.