-
Notifications
You must be signed in to change notification settings - Fork 642
Support query params? #95
Comments
I tried to eliminate the |
Thanks for the input, @mjackson |
i agree 100% now that we know we're not losing |
Obvious problem: we don't have access to |
IMO the correct solution here is your "always go through The conversion of location descriptors to locations is properly the responsibility of the In general it feels wrong to me to store location descriptors at all - they're really argument objects and not meant to be canonical, and it feels weird to me to do the location descriptor -> location conversion more than once (i.e. it should just be done once in |
Great input @taion, thanks! |
#104 is actually also a point in favour of always going through |
I think you should actually round-trip through the router, FWIW. The |
So, this would add support for getting query params from the router state in the redux store, but what about path params? Ex: getting the I know this is easy to do inside the React view itself with react-router, but I personally have use cases where I want to do things in my Redux reducers based on this information (without having to put logic in my view layer to dispatch actions based on changing Is the recommended approach for this to write helper methods to parse the full Why can't the state match the lovely |
If we stored more router state in the app state this still wouldn't help you. You don't have access to any other state in your reducer. It sounds like you want it in the
Because props has all sorts of things which do not belong in the app state; things that are unserializable and not dumb JavaScript objects. |
@jlongster Sure, if the I'm not suggesting one should store every (unserializable) prop from react-router, but the |
i am have a example using
link example: https://github.com/rackt/redux/blob/master/examples/real-world/containers/UserPage.js#L76 |
Yeah I think especially once we move to the new API, the right place to put this integration is going to be "below" the |
@taion thanks! |
@ngthorg What about something like this: function mapStateToProps(state, props) {
const { login } = props.params The second param to |
@taion New api? Got an issue or something that I could check out? Haven't had time to stay up-to-date with React Router and History lately. |
@taion neat, would love some help writing code when react-router updates. This library is pretty small and it would be nice to see what your ideal integration is. I understand that we're all busy though. |
@jlongster Something like... put the thing that listens to the router state under the |
We also need to trigger route updates though when redux state changes the routing state. I haven't studied the latest react-router changes so I don't know how that's going to work yet, but I'm totally fine with rewriting this if there's something better! |
That end can just be |
So, without the URL params in the redux store, like in redux-router, how do you currently handle the situation where you'd like to |
The asymmetry if you support params on the read side (but not the write side - you can't, without named routes) is annoying. |
@ryancole, your component's props should contain @connect((state, ownProps) => ({
product: selectProduct(ownProps.params.productId, state),
...
}),
actionCreators
) |
That's how I do it. We should put something like this in the docs. |
I had no idea that |
It would be nice to have access to params without needing to use react-router, in those cases where you still want to stuff routing in your store, but don't actually need full routing capabilities of react-router. |
@ezekielchentnik I think it's likely we will become more coupled to react-router, not less. Also, the tagline has always been:
|
@kjbekkelund Sure, that's fine to be coupled to react-router, and to leverage it internally, but we can't use react-router in redux directly... so if you want to update some redux state based on react-router Using @Dattaya's solution is only feasible when you want to directly render something based on the router state, not when you want to update redux state (ex: " |
It wasn't a good answer on my part, sorry. I'll try to add some context around the current state of redux-simple-router: Right now we only rely on Therefore, getting It would be awesome if someone played around with the ideas mentioned in this issue to see if there are nice solutions to the problem. We'd love to see a simple and clean solution that solves this. |
@kjbekkelund Got it. Thanks for the explanation! |
@kjbekkelund thanks for the info, makes sense. I'll take a stab, see what I can cook up. |
Is there a workaround to use query params currently? Or should I use route params instead? |
@akrawchyk If you are using In your component: |
You'd get something like this for close to free with #141 (with an appropriate API change to accept a location descriptor in your action creators) - just push through a location descriptor, and let the whole thing round-trip through |
So far the only way to use route params in a reducer seems to be an extra dispatch from a React component:
To be honest 'redux-router' doesn't support this either because it doesn't expose the action type that corresponds to route changes. One may hardcode it in a reducer but it feels dirty. |
@akorchev Query params don't go through the router at all. You're thinking router params. |
@taion yep. Ideally I should get them in my reducer when UPDATE_PATH happens. |
As discussed elsewhere, that might not strictly be possible - as it stands, |
@taion but it works in 'redux-router' - the only issue there is that they don't expose the action type corresponding to a route change - I have a |
here's my stab at using location descriptors, and supporting query params, rely more heavily on history api: https://gist.github.com/ezekielchentnik/261fef0f2f892ffce533 I shall create a PR |
There are a lot of comments above about the various details of how some parts of this would or wouldn't work, but I'm not sure I see any description of how someone would actually use this. What sort of API would be exposed? In my current app, I've done the query param synchronization in a very hardcoded way, and am looking to make it more generic. Essentially, there are two cases (in my app).
Checking if the query params have changed allows it to avoid infinite loops. Is the intention to have query params be stored in some separate part of the redux store or to allow me to expose any app state as a query param? (e.g., in my app I have a I can see making these two aspects separate modules, where Thoughts? |
@mindjuice The master version (not yet officially released) already supports query params (different from React-Router's router params) being stored in the redux-state because they now store the entire location descriptor from history. You can try it with |
My use case is very simple. Get a parameter and put it in the store. Say I have an array of items that are displayed in a component. I want to display the details of an item in a separate component which is in another route. Normally I would go to /itemDetails/itemId. All I want is to put the current item in the store so I can then use it from @connect.
|
@akorchev Its probably worth a new issue if you want to discuss react-router params which you are talking about with As for your specific case...I would offer an alternative approach. Your state update would not work with Something like (es6 with decorators syntax): import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
function mapStateToProps(state, ownProps) {
return {
// routeParams is passed down via props by React-Router
selectedItem: state.items.find(item => item.itemId === ownProps.routeParams.itemId)
};
}
@connect(mapStateToProps)
export default class ItemComponent extends Component {
static propTypes = {
selectedItem: PropTypes.object,
}
render() {
....
}
} Hit me up on Discord (or ask in the redux-router channel) if you have problems..I think further discussion is outside the scope of this issue |
@mjrussell that will work nicely! Thanks. Will it work with hot-reloading? |
This is now fixed in 2.0 🎉 |
@mjrussell What I want to avoid is having my selectors and reducers get any of their dependencies from I was thinking of having a couple of functions like If you're using reselect, then Still forming these thoughts, so they may be half-baked. 😄 |
@mindjuice I agree that you might want selectors to help you pull data out the |
@mjrussell I haven't used v2 yet, but I understand that it includes the full location object now and that query params are part of that. The issue for me is that routing data has to be in a specific location in the store. Sub-reducers and selectors in a given module don't get access to the whole store state, so they may not have access to I think the model should be that the reducers update the store state as necessary, but shouldn't care about the router query params at all. I think that should be a separate responsibility. I feel a bit like we're coming at this with different assumptions and maybe missing each other in the middle. |
@mindjuice ok, I can see how that could be difficult with your configuration. Its not clear to me yet what you are proposing as a change, although I do have some potential ways to tweak your config as alternatives.
|
This morning I've been playing around with how we could support query params in
redux-simple-router
(just as a thought experiment).In
history.listen
we receive aLocation
. WithpushPath
andreplacePath
we can change the API to acceptLocationDescriptor
s. However, with no way of creating aLocationDescriptor
object from aLocationDescriptor
string, it's difficult to support query params.Here's an example of the problem:
The problem is of course that every time you
pushPath
you will get the exactLocationDescriptor
you pass in into the store, but every time youhistory.push
or<Link>
you'll get an object. We then can't reliably support query params. (If you're very strict about always passing in aLocationDescriptorObject
you would have query support, but that feels very fragile.)We can of course use
history.createLocation
right now, but it's most likely no longer going to be public inhistory
V2.To support query params we need to be able to create a
LocationDescriptor
object both from aLocationDescriptor
string and from aLocation
. We could then easily support query params, and we could alsodeepEqual
check them without knowing aboutquery
or anything else that's actually part of theLocationDescriptor
(which is how we stop cycles, #50). With acreateLocationDescriptor
(that always returns aLocationDescriptorObject
) our code base would actually be simpler, and we would get query support for free.Okey, so some potential solutions:
Keep the solution we have now
I.e.
path
andstate
in store, but change to acceptingLocationDescriptor
inpush
andreplace
. We don't support query params.Verbatim
LocationDescriptor
in storeWe have to make it very clear that this is either an object or a string. So it's most likely not very usable for people. We "support" query params, iff you're very strict about always passing in a
LocationDescriptorObject
. Fragile.Always go through
history
"before" storeI.e. we don't trigger
UPDATE_PATH
immediately, but only within thehistory.listen
callback. We would then reliably have aLocationDescriptorObject
in the store, and we could therefore reliably support query params.This is of course a more complex solution.
Conclusion
It was interesting going through the different solutions, but with
createLocation
going away and nocreateLocationDescriptor
on the horizon I think it's best to just keep our current solution. I don't think it's worth the added complexity.Maybe someone else has ideas on how to solve this? Or maybe this is another case for keeping
history.createLocation
public? @jlongster @mjackson @taion @justingreenberg(Hopefully I haven't overlooked something very obvious 🙈)
The text was updated successfully, but these errors were encountered: