redux-persist
redux-persist copied to clipboard
Dynamic keyPrefix for Multiple Users
Hello!
I'm building an application that needs to store sessions for multiple users, and allow swapping between the users. After digging through issues folks have brought up here (especially #1047 and #637), I decided to do this with a replaceReducer with a new keyPrefix.
Essentially, this looks like:
function swapToUserStore(userId) {
const newConfig = {
...persistConfig,
keyPrefix: userId,
};
store.replaceReducer(persistReducer(newConfig, rootReducer));
}
This works well for swapping the stores; swapToUserStore(id) will cause a persist/REHYDRATE action to be dispatched with the associated persisted store of the userId keyPrefix.
However, the dispatch of the persist/REHYDRATE action occurs async, I believe as part of the initialization of reducers that occurs in replaceReducer, and I am unable to await the action to be dispatched or have a callback to it.
This is a problem because I don't have a guarantee on when to start using the newly hydrated store.
e.g. a login thunk:
function loginAction() {
return async (dispatch, getState) => {
const user = await loginApi();
swapToUserStore(user.id);
dispatch({ type: "LOGIN_SUCCESS", payload: user });
}
In that example, the LOGIN_SUCCESS action gets dispatched before the persist/REHYDRATE action.
Any thoughts on how to expect the persist/REHYDRATE synchronously? I've tried using .pause() and .persist() as well, but the same underlying issue exists where the action fired is async.
I'm considering implementing an action queue that releases when the persist/REHYDRATE action occurs, but this is also imperfect as the _persist property of the action does not include the keyPrefix, so there's no guarantee for associating the rehydrate action with the correct user (say, if multiple login attempts occur concurrently; this is no problem for handling concurrent thunks by keying the attempts, but the rehydrates would be identical).
For the time being, I'm working around this by simply causing a very short timeout after the the replaceReducer. This works as a proof of concept, but I'd prefer being able to have a more robust guarantee that the store has been properly swapped.
Any thoughts / feedback / limericks on this would be appreciated -- evidently other folks have been trying to use this library to implement multiple user sessions, I'm very curious how anyone else has gotten this working.
@JacobJaffe I'm facing a similar issue, actually I'm considering to have stores based on user id to avoid this kind of problems. But I'm not sure if this will be fine, as my user datas are big, and if 2 or 3 users logs on the same device, I don't want the datas of the other users to be loaded in my store. I've done the same thing as you do, a small timeout after user logged in, but you can also create a middleware that will handle rehydrate action and emit an event or just resolve a promise, this will help you to trick this problem. As a discussion, maybe we can find a way to update redux-persist api to handle that case properly.
@JacobJaffe @magrinj do either of you have code snippets for your solutions?
Sorry, no. TBH, I don't use this library any more.
I've come to find that treating the entire contents of a redux store as serializable storage isn't usually needed, and leads to syncing issues with server data stores.
I find it easier to use cache solutions like RTK query, and only save authentication + normalized entities to device storage now, manually.
For the use case I mentioned here, I now think that this isn't an ideal solution. When switching accounts, data should usually be either removed from device, or stored in a manner encrypted by the account. Offline concerns aren't relevant, since logging into a different authenticated account can be associated with network requests for hydration anyways.