-
Notifications
You must be signed in to change notification settings - Fork 866
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Having Rehydrated values passed in the store's initialState #21
Comments
I thought about this, and am definitely interested in supporting this, but upon initial inspection I found two issues:
It would seem the key to supporting this use case of initialState rehydration would be to provide a lower level What do you think? I think the value of redux-persist is that it provides a common extensible interface for rehydration, and in that vein / the spirit of redux, I would like to support the maximum use cases with the minimum api surface. |
Yes, I also found having initial -> rehydrated state transformation very useful for debugging and do want to use it for access token validation as well, but it has some drawbacks:
Having an asynchronous lower level getStoredState function for the initialState would be a solution, but we should avoid repeated rehydratation after initialization in this case. |
Well, those issues can be solved by just returning the store asynchroniously in the persistStore callback. The downsides of this approach are that the rendering is slower (but with getStoredState it would be almost the same) and the states are still stored in the storage again (because they are changed from the initialState). A solution to the latter could be to move |
I have only partially formed thoughts on these very good points you raise:
I also added a debounce config parameter (in in versions >=1.1.0). From my initial test debounce: false works great. It has occured to me that crosstab-sync implicitly depends on the fact that string equality exists in the serialized state post-rehydration. This may not be the case in |
Also regarding the question at hand or initialState, one possible api for this could be import { getStoredState, storeStateOnChange }
//...
const store = createStore(reducer, getStoredState())
storeStateOnChange(store) The problem is, getStoredState would only work as described with a sync api, namely localStorage. I am not sure any elegant way to do this with an async storage api. |
Thanks a lot for the changes! I'll look into it. I like the current approach of using async storage API, and see 2 big advantages for a web app:
Regarding initialState, we shouldn't enforce any promise library, so it would be only one solution - to get the store in a callback: export default function configureStore(callback) {
getStoredState(initialState => {
const store = createStore(reducer, initialState)
storeStateOnChange(store)
callback(store)
})
} And then use it like that: import React from 'react'
import { render } from 'react-dom'
import Root from '../containers/Root'
import configureStore from '../store/configureStore'
configureStore(store => {
render(
<Root store={store} />,
document.getElementById('root')
);
}); I'm still not sure whether we need it if the previous issues are solved. |
Would the above snippet (react rendering in an async callback) not also cause selenium testing issues? I definitely like where you are going with this, and I think there are a (minority) of projects that will find this approach better suited. Code wise implementation will be trivial, just need to expose existing functionality via two new methods. Since this has turned into a full blown api review I have a few questions:
|
It suits well selenium tests as we already wait till the page is loaded/rendered. Actually, it was possible before to add an additional waiting while we get the necessary value, but if it fails, it would be difficult to figure out what caused the issue.
|
|
Ok just pushed an update with a new Here is the gist: import { getStoredState, persistStore } from 'redux-persist'
const config = {
skipRehydrate: true
}
getStoredState(config, (err, initialState) => {
const store = createStore(reducer, initialState)
persistStore(store, config)
render(
<Root store={store} />,
document.getElementById('root')
</Root>
)
}) Of course this can be split up essentially the same as in your comment, except with an error first callback and Overall I am pretty happy with this approach, and the symmetric config makes things easy. Also interestingly it opens up the possibility for secondary persistence schemes. e.g. // main persistor using localForage
let mainPersistor = persistStore(store)
let remotePersistor = persistStore(store, {storage: secondaryServerStorage, shouldRehydrate: false}) This could trivially enable cool features like observing user sessions - just hook up an instance of your app to the remotePersistor (identified by some user id). |
Just tested, that's awesome! The only problem I see, if we have |
@zalmoxisus ah yes, that was an oversight. A lot of ambiguous terms floating around, if you have suggestions for more explicit naming I am all ears. For now I will change |
renamed config to |
facepalm I added tests on the persistStore side, forgot about autoRehydrate. Will fix asap |
persistStore now emits REHYDRATE_COMPLETE even if While inelegant, this is the only non-error prone way I can see to preserve the action buffer (which is very useful in a naive implementation). Actually emiting a completion action is useful, the problem is it should be renamed to something more accurate, since no rehydration occured. |
note there is still one gotcha, if you do not call |
Thanks a lot! Another advantage of this new approach is that now redux-persist is compatible with redux-devtools' persistState (before the history was reset on the initial rehydratation). It is the only case where having |
👍 I have not used redux-devtools much as I am mostly in react-native atm. |
@rt2zz, is it ok to not include autoRehydrate store enhancer at all if I use the current scenario and don't have hydratations from such libraries as redux-persist-crosstab? |
@zalmoxisus yes, in fact it is preferable not to use autoRehydrate in this case. |
@rt2zz What is the solution for immutable.js type states? I'm trying this solution with redux-persist-transform-immutable but it gives error about type mismatch. #21 (comment) |
I still looking into it, but it would be great to achieve. Now the reducers are initiated twice: the first one with the initial value, and the second - with the rehydrated one. I tried to find some solutions, but all of them seems to be antipattern, except of this. Actually, this is the purpose of the store's initialState to pass the rehydrating state from server or localStorage.
What do you think if we get the data from the localStorage before creating the store?
The text was updated successfully, but these errors were encountered: