keajs / kea-router

Router for Kea
MIT License
6 stars 4 forks source link

An idea of url query sync #3

Open kairyu opened 4 years ago

kairyu commented 4 years ago

Thank you for the great works. I really like the concept of Kea and recently I'm working on my second project with Kea.

In the project I have a requirement to sync between url query string and store. I have been looking for and tried several existing libraries which have similar concept, but none of them meets all my requirements.

So I decided to implement one by myself based on Kea's powerful plugin system, but I realized on the way that it has some overlaps with kea-router (listening to url changes and operating url) and has to cooperate with kea-router (to avoid unnecessary changes to query string), so eventually I merged the codes into kea-router.

I noticed that you are also working on hash and search recently, so I would like to share my works as an immature idea of a different approach to manage query parameters. I hope this will be of some help.

Source code: https://github.com/kairyu/kea-router/tree/url-query-sync Example: https://github.com/kairyu/kea-router-query-sync-example

The concept is to consider url (especially query string) as a View component in Flux pattern:

The usage:

import { kea } from 'kea'

export const articlesLogic = kea({
  actions: () => ({ ... }),

  reducers: () => ({ ... }),

  urlQuerySync: ({ selectors, defaults, actions }) => ({
    text: {  // key of query parameter, ?text=xxx
      path: '/input',  // only works on matched url pathname
      selector: selectors.text,  // selector for getting current value from store
      defaultValue: defaults.text,  // if current value is equal to defaultValue, remove this parameter from query string
      push: true,  // pushState or replaceState when value is changed, default is replaceState
      action: actions.setText,  // action dispatched when query parameter is changed
      resetAction: actions.resetText,  // action when query parameter is removed from query string
      valueToString: (value) => ( ... ),  // function used to format value to query string, default is v => `${v}`
      stringToArguments: (string) => ([ ... ]),  // function used to parse query string to arguments passed to action, default is s => [s]
    },
  }),
})

The codes is not completely tested. Some of the implementations are influenced by the following projects:

mariusandra commented 4 years ago

Hey, that's pretty cool work! :)

Yes, I recently had to add support for the search and hash URL parameters, as I needed them for a big refactoring PR I was working on.

I'm currently also working on a big rewrite for Kea's documentation, so while it's not yet live on kea.js.org, you can read about the searchParams and hashParams router upgrades here in case you didn't see it yet.

I think with it it's quite easy to keep the URL and a reducer in sync.

import { router } from 'kea-router'

kea({
  actions: () => ({
    setParams: params => ({ params })
  }),
  reducers: () => ({
    params: [{}, {.
      setParams:  (_, { params }) => params
    }]
  }),
  actionToUrl: () => ({
    setParams: ({ params }) => [router.values.location.pathname, params],
  }),
  urlToAction: ({ actions }) => ({
    [router.values.location.pathname]: (_, searchParams) => setParams(searchParams)
  })
})

I didn't test the code above, but I guess it should work :).

It's perhaps even easier if you just use router.selectors.searchParams to get your params and router.actions.push(router.values.location.pathname, newParams) to push new params :).

In any case, it's great to see the work you've done here. I hope the new changes in kea-router can make your life somewhat easier as well :)