React-router: Make location.query always be an object

Created on 18 Sep 2016  路  11Comments  路  Source: ReactTraining/react-router

So far I'm liking v4. However, this detail stood out to me.

Making location.query _always_ be an object would save us from having location.query || {} all around our code. I can't think of any scenarios in which I'd find a null location.query useful. If you wanted to check if there's no query param, you could use !location.search.

Having location.query always be an an object means you don't have to perform the extra conditional check whenever you want to read a value. I think that the common use-case would be to try reading a query param value, and use a default fallback when the the value is missing.

Some prior art that shares this behavior:

  • url.parse from node's built-in modules will return an empty object when parseQueryString is true (it uses querystring.parse, which always return an object)
  • qs.parse will always return an empty object
  • req.query from express is always an object
  • window.URL will always set url.query to a URLSearchParams object
bug

Most helpful comment

@ryanflorence Would it be possible for an empty query to be set to undefined instead of null so we can use defaults in destructuring?

const Component = ({ location: { query = {}}}) => {
    const {
        foo,
        bar,
    } = query
    ...
}

All 11 comments

Can you open up a PR to implement this? It sounds sensible.

I've spent some time thinking of this for a long time (since before this issue) and I'd like to keep it null for now, I can't think of any reason yet, but it's possible right now to check if there is a query at all or not, which might one day be important.

If we implement this feature request, and then one day realize "oh crap, we really do need a way to know if there is a query" then we have to make a pretty devastating API change for apps.

If we leave the API as is, then when we add this feature, apps won't break.

So, I'm going to 馃憥 this for now. Not because it isn't sensible, but because I'm sensitive to API changes in the future.

Also, consider state works the same way as query right now.

Actually, here's a use case:

<Link
  to="/"
  activeStyle={{ color: 'red' }}
  isActive={(location) => (
    location.query == null
  )}
>No query</Link>

That link will be active if there isn't a query.

I think in general what we're going for as far as API is less-is-more. React doesn't add convenience API like componentDidRender even though we often do the exact same work in cDM and cDU.

@ryanflorence Would it be possible for an empty query to be set to undefined instead of null so we can use defaults in destructuring?

const Component = ({ location: { query = {}}}) => {
    const {
        foo,
        bar,
    } = query
    ...
}

Can we please get a response from someone managing the project? I think the idea of using undefined over null is a reasonable compromise.

@Munksey Query parsing is completely gone in 4.0 currently. You can receive location.search over context and parse it however you'd like. You can also modify history to add back query parsing. There are a few options here.

@timdorr is there any plan to add query parsing back into 4.x or will parsing location.search be the new norm?

No plans. It bloats the library size and is opinionated. There are many ways to parse query strings (particularly surrounding arrays), so we don't want to prescribe a solution that might not work your environment.

Sorry if this is naive in some way, but isn't parsing a string - which is the exact same in all browsers by a standards definition -kind of necessarily opinionated?

There is no actual spec for query strings. Query strings are almost always name value pairs, but they don't have to be. ?1290832190213 is a valid query string.

Assuming that query strings did have to use the common format (?name1=value1&name2=value2), you still run into issues when you want to express more complicated structures in the query.

For example, you might want to turn the object { x: { y: { z: 'hi' }}} into a query string. With qs, that could be ?x[y][z]=hi or ?x.y.z=hi (but only if you use the allowDots option). However, query-string and querystring do not support objects in query string, so if you try to pass either of the above strings to them, they will fail.

Thanks! I didn't consider complex objects in query strings.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nicolashery picture nicolashery  路  3Comments

jzimmek picture jzimmek  路  3Comments

yormi picture yormi  路  3Comments

sarbbottam picture sarbbottam  路  3Comments

misterwilliam picture misterwilliam  路  3Comments