I'm working on a React/Redux application and I am having issues with my state. I'm using redux-persist in order to rehydrate my store in the event of a page refresh. I'm using peerJS to broker connections between users who are streaming and those that are viewing.
On user login, I create a new peer object, and then update my redux store. The problem is that redux-persist can't serialize the peer object. It seems that in the peer object there are (random?) letters after the object key, but before the value. During development when I make changes and the app refreshes, the peer object is no longer in my Redux store.
Ex:
_events: n
__jsogObjectId: "19"
I think the n (and similar letters in other places) is where my problem starts.
After doing some research, I came across this on GitHub: https://github.com/rt2zz/redux-persist/issues/644#issuecomment-600760196
And I tried to implement the solution the same way.
export const JSOGTransform = createTransform(
(inboundState, key) => JSOG.encode(inboundState),
(outboundState, key) => JSOG.decode(outboundState)
);
const persistConfig = {
key: "root",
storage: storage,
stateReconciler: autoMergeLevel2,
transforms: [JSOGTransform],
};
But it's still not working. It seems that it's addressing a slightly different problem. I don't think it accounts for the extra letters like this. I've tried using the transform in my root persistConfig, as well as the config for the specific key where the peer object would be stored. Neither have worked for me.
Here is the code for my store:
// Import reducers
import userReducer from "./reducers/userReducer.js";
import accountReducer from "./reducers/accountReducer.js";
import streamReducer from "./reducers/streamReducer.js";
// Create transform
export const JSOGTransform = createTransform(
(inboundState, key) => JSOG.encode(inboundState),
(outboundState, key) => JSOG.decode(outboundState)
);
const persistConfig = {
key: "root",
storage: storage,
stateReconciler: autoMergeLevel2,
transforms: [JSOGTransform],
};
const userPersistConfig = {
key: "User",
storage: storage,
stateReconsiler: autoMergeLevel2,
};
const accountPersistConfig = {
key: "Account",
storage: storage,
stateReconciler: autoMergeLevel2,
};
const streamPersistConfig = {
key: "Stream",
storage: storage,
stateReconciler: autoMergeLevel2,
};
const rootReducer = combineReducers({
User: persistReducer(userPersistConfig, userReducer),
Account: persistReducer(accountPersistConfig, accountReducer),
Stream: persistReducer(streamPersistConfig, streamReducer),
});
const customPersistReducer = persistReducer(persistConfig, rootReducer);
export const store = createStore(
customPersistReducer,
compose(
applyMiddleware(thunk, logger),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export const persistor = persistStore(store);
What is the best way to address this problem? And more broadly, am I going about this the right way? It made sense to me at the time to update my store with the peer object, because I need the unique id for connections between users. But if storing it is a problem, what would be the smart way to approach this issue?
I'm trying to use Redux on a more complicated application. I don't mind re-writing things as long as I'm learning, and moving towards industry best practices.
1/16/21 Update: I opened an issue on the PeerJS repo to try and get an answer about the extra letters. However I would appreciate any feedback regarding how I'm approaching the problem as well.
Redux is really just meant to store & manage data for you, not class instances. Class instances add all matter or problems: They serialize badly (like you encountered) and also they often change their own properties outside of the redux data flow, which leads to all kinds of unspecified behaviour. Also, it often breaks the devtools.
This is why the redux style guide says Do Not Put Non-Serializable Values in State or Actions.
What you are looking for here for this class instance is really not a state management solution (because that class instance is not really state), but a depenendency injection mechanism.
Luckily, React comes with a dependency injection mechanism: Context. And yes, this is really what context is meant for: making one object available to the child components in your application. So, my advise would be to keep your data in redux and go for context for things like this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With