Reputation: 1304
I'm having a few issues with persisting Redux
in React using React-Redux
and Redux-Persist
.
Reducer Example:
export default (state = {}, action) => {
switch (action.type) {
case "SET_FOO":
return action.payload
default:
return state;
}
};
Action Example:
const setFooAction = (payload) => {
return {
type: "SET_FOO",
payload
}
}
export default setFooAction;
Index.js
import { createStore, combineReducers } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage";
import { PersistGate } from 'redux-persist/integration/react'
import fooReducer from "redux/reducers/setFooReducer";
const persistConfig = {
key: "root",
storage
};
const rootReducer = combineReducers({
foo: fooReducer
});
const persistedReducer = persistReducer(persistConfig, rootReducer);
let state = {
foo: {}
}
let store = createStore(
persistedReducer,
state,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
let persistor = persistStore(store);
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
document.getElementById("root")
);
Usage in component:
import { connect } from "react-redux";
import setFoo from "redux/actions/setFooAction";
class Main extends Component {
//... More Code
componentDidMount() {
let foo = this.getFoo() //Gets foo, doesn't really exist but just for context
this.props.setFoo(foo); //Works fine, all gets set, data is persisted
}
addNewFoo = () => {
//Called after functions runs somewhere
let newFoo = this.getNewFoo() //Gets newFoo, doesn't really exist but just for context
foo.push(newFoo)
this.props.setFoo(foo); //Sets Redux store, on refresh, doesn't persist
}
//...More Code
}
const mapStateToProps = (state) => ({
...state,
});
const mapDispatchToProps = (dispatch) => ({
setFoo: (payload) => dispatch(setFoo(payload))
});
export default connect(mapStateToProps, mapDispatchToProps)(Main);
Initially, everything works fine:
PERSIST
fires, and it's stored in local storage.However...
If I decide to add anything new into my objects and set/update them into the Redux store...
... on refresh, only what was originally persisted is still present during REHYDRATE
(if I am understanding the Redux events right).
Now I believe this is something to do with my objects immutability and Redux not picking up changes because of that, but I have attempted to alter my reducers without any luck:
Reducer Attempt:
export default (state = {}, action) => Object.assign(state, {
foo: action.payload !== "SET_FOO" ? state.foo : action.payload
});
I tried the above (and also a combintation of this and my original which just broke things). This sort of worked, but was setting my state as follows:
state {
foo: {
foo: {
//Foo data
}
}
}
I know that it's just assigning to foo
again because of the addition foo:
in the reducer...
...however, I am unsure how to correct this without potentially doing something wrong in Redux
!
So, my caution has prevailed and I thought best to ask if anyone has any suggestions or threads that I can pull at!
Thanks for any help in advance!!!
Upvotes: 0
Views: 1411
Reputation: 420
Everything seems good at first glance.
Your Object.assign
in the reducer may be what is causing the nested foo
objects, because of one on Redux principles that is immutability so you should always return a new state, instead, you're mutating directly the state
.
You can add one first parameter more, to create a new object that will have the state properties with the new foo one:
export default (state = {}, action) => Object.assign({}, state, {
foo: action.payload !== "SET_FOO" ? state.foo : action.payload
});
A better approach and that you will see often will be:
export default (state = {}, { type, payload }) => {
switch (type) {
case 'SET_FOO': {
return { ...state, payload }
}
default: {
return state
}
}
}
In this last example, you can clearly visualize that I'm returning a new object with all the properties that the state has, plus the new payload.
Good luck!
Upvotes: 2