I have a basket reducer which contains my shopping basket and basket content would be something like this:
basket: {
32012: {
title: "foo",
count: 1
},
32013: {
title: "bar",
count: 1
}
}
I persist it with redux-persist, it's working good when a new object has been add or remove from basket array, but when I update a child like this:
basket: {
32012: {
title: "foo",
count: 4
},
32013: {
title: "bar",
count: 5
}
}
after refreshing page count would be 1 for each item!
here is my rootReducer:
import {combineReducers} from 'redux';
import {persistReducer} from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import basketReducer from '../ducks/basket/reducers';
const basketPersistConfig = {
key: 'basket',
storage: storage,
};
const rootReducer = combineReducers({
basket: persistReducer(basketPersistConfig, basketReducer)
});
export default rootReducer;
I also tried hardSet, autoMergeLevel1, and autoMergeLevel2 but nothing happened!
Can you please provide the code you use into your reducer to update your nested state ?
Also can confirm it.
I have store where user reducer contains several nested reducers e.g. state, friends, profile. State is where I store current user state - logged in/out, username, token, etc.
If I whitelist whole user reducer in PersistConfig so e.g.
const persistConfig = {
key: 'root',
storage,
whitelist: ['router', 'cms', 'user'],
blacklist: ['form'],
debug: (config.env === 'development'),
}
and then call SIGN_OUT action which basically resets user.state it works. Reseted data is saved in persist storage and later on reused.
But with this I store whole user store section which in some cases might be large.
So recently I switched to nested persisting and right now my main config looks like this:
const persistConfig = {
key: 'root',
storage,
whitelist: ['router', 'cms'],
blacklist: ['form'],
debug: (config.env === 'development'),
}
in rootReducer I switched use nested persist configuration as follows:
const appReducer = combineReducers({
// ...some other reducers
// user, // <-- old way
user: persistReducer(userPersistConfig, user), // <-- new way/setup
})
where my userPersistConfig is as follows:
const userPersistConfig = {
key: 'user',
storage: storage,
whitelist: ['state'],
stateReconciler: hardSet,
}
My root reducer has this kind of solution for signing user out:
const rootReducer = (state, action) => {
switch (action.type) {
case 'SIGN_OUT':
return appReducer(undefined, action)
default:
}
return appReducer(state, action)
}
And now whatever I would set to stateReconciler (in userPersistConfig) it just doesn't save to persist storage. After page refresh redux-persist rehydrates user.state with old data (prior SIGN_OUT). I see persist/REHYDRATE is executed twice:
router and cms (those are whitelisted))Is it possible to force nested persist to save data always?
@rezaerami Maybe you are updating existing basket objects in the basket reducer? Make sure that when you are updating basket count, you are not mutating existing objects but you create new objects. You can test it quickly by var newState = JSON.parse(JSON.stringify(state)); and then updating newState and returning it in the basket reducer.
https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns
I have the exact same problem, did you manage to work with redux-persist?
Our session is a jwt object. The jwt object can be saved once, the second time the redux store is updated but not the localStorage, this break our app.
Any idea why? That's problematic because it's the jwt and auth strategy on my client.
Thanks @iqqmuT you saved me!
I saw a similar problem, even by stringifying and parsing the state.
Anything that is an array or an object is not saved to AsyncStorage (if the state is a mix of number, strings, arrays and objects, only numbers and strings are saved). As if only the first level is saved, but not recursively?
@mbrucher, Have you got any solution to this problem? I am having a similar issue with redux-persist.
well, it's been a long time since then and I don't actually remember how did I solve it.
but what I remember is I had a really bad store architecture.
so I wrapped out the count and other updatable properties, in fact, I flattened the object of each product in the basket.
const basket = [
{
id: 1,
foo: 'bar',
count: 1,
}
]
so i seperated the count from the product original properties like this
const basket = {
1: {
id: 1,
foo: 'bar',
}
}
const badges= {
1: {
count: 1
}
}
so they are related by the key of the object.
but it's not the best solution. I faced it several times and handled it better
if you write the reducer correctly this problem would not happen
wrong reducer:
const basketReducer = (state = {}, action) => {
switch (action.type) {
case 'ADD_TO_BASKET':
state[action.payload.id].count = action.payload.count;
return state;
default:
return state;
}
};
fixed reducer:
const basketReducer = (state = {}, action) => {
switch (action.type) {
case 'ADD_TO_BASKET':
return {
...state,
[action.payload.id]: {
...state[action.payload.id],
count: action.payload.count,
},
};
default:
return state;
}
};
@Gopes396
Most helpful comment
@rezaerami Maybe you are updating existing basket objects in the basket reducer? Make sure that when you are updating basket count, you are not mutating existing objects but you create new objects. You can test it quickly by
var newState = JSON.parse(JSON.stringify(state));and then updatingnewStateand returning it in the basket reducer.https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns