metosin / reitit

A fast data-driven routing library for Clojure/Script
https://cljdoc.org/d/metosin/reitit/
Eclipse Public License 1.0
1.42k stars 255 forks source link

handling front-end internal redirects easily? #509

Open WorldsEndless opened 3 years ago

WorldsEndless commented 3 years ago

We have long wondered how to handle an internal redirect without using a javascript go-to, which issues a refreshing browser command -- this is, after all, what Reitit manages with keyword hrefs. We were delighted to find an example that has just the function we wanted:

https://github.com/metosin/reitit/blob/1ab075bd353966636f154ac36ae9b7990efeb008/examples/frontend-links/src/frontend/core.cljs#L23

Two questions arose, then:

  1. What should those arg maps look like? I assume args like query-params and path-params look like what you deal with when handling routes themselves, but is there a formal description somewhere?
  2. Why isn't redirect included in the actual frontend.easy code? Why is it only in an example test? Seems like it should qualify as "easy"
Deraen commented 2 years ago

Check the implementation:

  (if push
    (rfe/push-state to path-params query-params)
    (rfe/replace-state to path-params query-params)))

push- and replace-state have docstrings that should describe parameters.

I don't remember why this function exists in the example, I think just using push-state directly is much cleaner. Redirect is a very loaded term and just makes it harder to understand what is happening.

WorldsEndless commented 2 years ago

I haven't fully worked it out yet, but I believe the answer is here: https://cljdoc.org/d/metosin/reitit/0.5.15/doc/frontend/browser-integration#anchor-click-handling

Thanks to wevrem@clojurians.slack

WorldsEndless commented 2 years ago

I'm still looking for the answer here. I have been able to customize the click handling, but still no luck figuring out how to do an internal routing job exactly like when an href is clicked, but minus the click. The function I imagine is something like (internal-goto :my-route-ns/my-route) and go to that route, with all the handlers, url changes, and controllers associated with that route.

Deraen commented 2 years ago

I don't remember Location API having goto method but perhaps you refer to window.location.assign or window.navigate, or just location.href = '/new-path'.

With hash routing, you cloud just assign window.location.hash new value directly, and it doesn't cause reloads because updating hash doesn't change path.

Generic way to update browser location is to use pushState (or replaceState) to update browser location. These don't trigger reload.

The matching reitit functions build the new url with given route name and parameters using href and then update location and call the exactly same methods as updating the location by clicking a element would.

[:button {:on-click (fn [_] (.then (some-async-call)
                                   (fn []
                                     (rfe/push-state :my-route-ns/my-route
                                       {:path-param-a 1}
                                       {:query-params-b 2}))))}]

And of course the push-state could from anywhere.

The documentation mentions this very tersely:

Functions follow HTML5 History API: push-state to change route, replace-state to change route without leaving previous entry in browser history.

We could probably further expand that these take the same parameters as href function.

And the API docs were already improved in 0.5.16 (2022-02-15): https://cljdoc.org/d/metosin/reitit/0.5.17/api/reitit.frontend.easy