Closed raineroviir closed 8 years ago
Hi @raineroviir,
There are two things you can do about the namespace issue.
import { devTools } from 'redux-devtools';
import persistState from 'redux-localstorage'; // ~v1.0.0 (beta)
const finalCreateStore = compose(
devTools(),
persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)),
createStore
);
Works exactly the same as:
import { devTools, persistState } from 'redux-devtools';
const finalCreateStore = compose(
devTools(),
persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)),
createStore
);
There is however a different conflict/issue when you're using dev-tools and that's the fact that dev-tools "lifts" your store state. In other words, your store doesn't have the shape you would expect it to, based on your reducers. If you're persisting your complete store state (in dev and in production) there isn't any issue, but it falls apart if you only want to persist a subset of your store state (in production).
This is something I still have to look into further, to see if an elegant solution can be found (or at least a recommended way of doing things..). How are you enabling dev-tools while developing and disabling/removing it when in production? - that may very well provide the means to configure persistState differently to meet your needs, both in production and while developing using dev-tools.
Thank you very much for the thorough explanation. I am not enabling/disabling dev-tools in production, but I will cross that bridge soon
import persistState from 'redux-localstorage'
....
if (__DEVELOPMENT__ && __CLIENT__ && __DEVTOOLS__) {
let devtools = require('redux-devtools');
finalCreateStore = compose(
applyMiddleware(middleware),
devtools.devTools(),
persistState(/*paths , config*/),
devtools.persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)),
createStore
);
} else {
finalCreateStore = compose(
applyMiddleware(middleware),
persistState(/*paths, config*/),
createStore
);
}
Hey @snackycracky , this doesn't really work for me. In development, the state that I want to filter is deeply nested in a { computedStates: [{state: { stuff I want to get to }]}
, so the keys I provide to filter
don't reconcile. This is @elgerlambert was alluding to above. I think you'd almost have to have a redux-devtools-filter
adapter to return the last computedStates[last].state
, which I guess wouldn't be that bad since it'd only be a dev dependency.
fully prepared to be wrong on this and doing something stupid
Hi @ruprict, thanks for the gist. The conclusion I had come to is that it doesn't actually make any sense to filter
the state you want to persist when you're using dev-tools
. If you do, it would break the ability to replay/reload a previous dev-session since you didn't persist what it needs.
If alternatively, you persisted both everything that dev-tools
needs, as well as a filtered
section of state that you ultimately want in production, then the state persisted by dev-tools would override whatever filtered
state you persisted.
Thinking about it while I write, the use case that remains and is probably what you're after; if you start a session with e.g. http://localhost:3000/?debug_session=123
you want to persist everything that dev-tools needs, but if you just went to http://localhost:3000/
, you'd want to see the behaviour you expect in production. Is that correct?
Hey @elgerlambert, cheers for replying.
So, if the dev-tools are persisting everything under the key redux-dev-session-&debug_session=123
, and redux-localstorage
is filtering out what I want under a differen key (like, redux-localstorage
), then this seems to work.
I get both keys, the state looks like I’d think. I am persisting both states:
var storage;
if (process.env.NODE_ENV === 'development') {
storage = compose(
devToolsFilter('auth'),
adapter(localStorage)
);
} else{
storage = compose(
filter('auth'),
adapter(localStorage)
);
}
...
var middleware = clientMiddleware(client), finalCreateStore;
if (process.env.NODE_ENV === 'development') {
let devTools = require('redux-devtools');
finalCreateStore =
compose(
applyMiddleware(middleware),
devTools.devTools(),
persistState(storage, 'esalerugs'),
typeof window !== 'undefined' ?
devTools.persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)) :
identity,
createStore
)
} else
finalCreateStore = applyMiddleware(middleware)(createPersistentStore);
I am not sure if this breaks something else, but it's "working" for me. What I want is for the dev to act like prod from the localStorage perspective, regardless of the dev tools being enabled.
I apologize if I am being obtuse. I am still swimming a bit in the deep end with redux/react/etc.
Thanks @ruprict, yeah you've essentially created the last scenario that I was describing in my previous comment. Rather then creating a special devToolsFilter that replicates everything that filter does you can create the following (significantly simpeler!) storage enhancer:
function unliftState(liftedState) {
const { computedStates, currentStateIndex } = liftedState
const { state } = computedStates[currentStateIndex]
return state
}
export default function unliftDevToolsState(storage) {
return ({
...storage,
put: (key, state, callback) => {
storage.put(key, unliftState(state), callback)
}
})
}
With this storage enhancer you would change your snippet above to the following:
if (process.env.NODE_ENV === 'development') {
storage = compose(
unliftDevToolsState,
filter('auth'),
adapter(localStorage)
);
} else{
storage = compose(
filter('auth'),
adapter(localStorage)
);
}
Make sure unliftDevToolsState
comes before filter
.
The code above is untested, but should do the trick, try it out and let me know :). I still plan on looking into this further and will keep an eye on dev-tools to see how it evolves, but I guess the unliftDevToolsState
storage enhancer offers a solution for now. I will leave this issue open to continue the discussion around dev-tools and welcome any suggestions!
Btw, does the order of persistState and devTools.persistState matter (inside your finalCreateStore
compose
)? Does it break if you switch them around?
@elgerlambert works great! Thanks!
The order doesn't seem to matter, nothing breaks when I switch them.
Looks like the unliftDevToolsState
storage enhancer isn't actually needed. If you place redux-localstorage's persistState
above devTools
everything appears to be working as it should:
import {devTools, persistState as persistDevToolsState} from 'redux-devtools'
import persistState from 'redux-localstorage'
import adapter from 'redux-localstorage/lib/adapters/localStorage'
import filter from 'redux-localstorage-filter'
const storage = compose(
filter('key')
)(adapter(window.localStorage));
const createPersistentStoreWithDevTools = compose(
persistState(storage, 'my-storage-key'),
devTools()
persistDevToolsState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
)(createStore);
It also solves a different issue whereby devTools
swallows the redux-localstorage/INIT
action.
ref: https://github.com/elgerlambert/redux-localstorage/issues/5#issuecomment-137128656
Note: the above gist is based on redux-localstorage@1.0.0-rc
and redux@2.0.0
redux-devtools
currently usespersistState
as a module, which conflicts with this module'spersistState
. Any way I can use both of these addons?Thanks