nareshbhatia / mobx-state-router

MobX-powered router for React apps
https://nareshbhatia.github.io/mobx-state-router/
MIT License
227 stars 30 forks source link

Add Support for Bracket Format URL Query Array Parameters #64

Closed cmolenda closed 4 years ago

cmolenda commented 5 years ago

Problem Bracket formatted array values in query strings do not return arrays in the toState of routes onEnter callback.

Request Allow users to specify which parsing format the query-string library uses

Details When using this module in conjunction with a server framework such as Rails, the server's query string format for array values uses the pattern keyName[]=value. E.g. for users 1,2,3, the query string is ?users[]=1&users[]=2&users[]=3.

The query-string library used in the HistoryRouter and StaticRouter has this capability, but it does not look like it is exposed.

Since the library's default query mechanism is being used, the toState for an onEnter hook for the string ?status=enabled&userIds[]=1&userIds[]=2&userIds[]=3 results in the object { status: "enabled", users[]: 3 }

Example routes.js

// URL: `http://www.example.com/users?userIds[]=1&userIds[]=2&userIds[]=3`
export const routes = [
  {
    name: "users",
    pattern: "/users",
    onEnter: (fromState, toState, routerStore) => {

      // Won't work. All userIds will be replaced by one field `{ userIds[]: 3 }`
      const { queryParams: { userIds } } = toState;

      routerStore.rootStore.setUserIds(userIds);
    },
  },
];

Current Workaround Use the global window location.

import queryString from "query-string";

// URL: `http://www.example.com/users?userIds[]=1&userIds[]=2&userIds[]=3`
export const routes = [
  {
    name: "users",
    pattern: "/users",
    onEnter: (fromState, toState, routerStore) => {

      // Works. Results in `{ userIds: [1,2,3] }`. Note the options passed to queryString
      const params = queryString.parse(window.location.search, { arrayFormat: "bracket" })

      routerStore.rootStore.setUserIds(params.userIds);
    },
  },
];
nareshbhatia commented 5 years ago

Thank you for this great suggestion, @cmolenda. I am open to exposing the full capability of query-string. Let's work on an API for this.

My initial thought is to allow parse() and stringify() to be passed in as options. I would also change the RouterState definition as follows:

class RouterState {
    constructor(
        readonly routeName: string,
        readonly params: {[key: string]: string} = {},
        readonly queryParams: {[key: string]: any} = {}
    ) {}
}

Finally, I would upgrade the query-string dependency to 6.x.

Please let me know your thoughts.

nareshbhatia commented 4 years ago

Hi @cmolenda, this feature has been added in version 5.0.0-beta.5. You can now pass query-string parse options as well as stringify options to the RouterStore. See here.

Please note that version 5 has a few breaking changes to simplify the APIs. You can find a change log here. Feedback welcome!

cmolenda commented 4 years ago

Excellent work! And very easy to understand spec, too: https://github.com/nareshbhatia/mobx-state-router/commit/61eeb475d490afe8bc70552c4d67000d78185aed#diff-47052a903b896d9f6a8eacf0c7c690acR70 😄

Thank you for this.