This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-01-03
Channels
- # adventofcode (2)
- # announcements (1)
- # asami (35)
- # babashka (67)
- # beginners (97)
- # cherry (3)
- # clj-yaml (3)
- # cljsrn (9)
- # clojure (44)
- # clojure-dev (34)
- # clojure-europe (13)
- # clojure-gamedev (1)
- # clojure-norway (10)
- # clojure-uk (2)
- # clojurescript (24)
- # clr (1)
- # conjure (18)
- # cursive (4)
- # datalevin (3)
- # emacs (6)
- # graalvm (9)
- # graphql (1)
- # introduce-yourself (1)
- # malli (7)
- # nrepl (3)
- # portal (1)
- # quil (2)
- # reagent (1)
- # reitit (21)
- # releases (1)
- # reveal (11)
- # ring (2)
- # shadow-cljs (17)
- # sql (24)
- # vim (4)
I'm trying to migrate a big frontend (re-frame) app to reitit and struggling with programmatically navigating to a new path (what useNavigate
and navigate
functions do in react-router
/`remix`). Details in thread
It's on a catch-all route apps/*app-path
, what I tried:
1. Following the repo example frontend-re-frame I used ::navigate!
effect handler calling rfe/push-state
with route name, path-params and query-params (after matching by path for the new route). Problem: the catch-all path-params
is {:app-path: "some/app"}
where the /
becomes URI encoded to some%2Fapp
resulting in the wrong browser URL.
2. Tried to manually call (.pushState js/window.history nil {} "/apps/some/app")
doesn't push new history entry? I cannot navigate back. When using fragment router this manual push and navigating back does work.
3. Also tried to manually call -on-navigate
similar to how it's done in the reitit code base for push-state, no luck either:
;; pushState and replaceState don't trigger popstate event so call on-navigate manually
(.pushState js/window.history nil "" (-href history path))
(-on-navigate history path))
At the point where I think I misunderstand something fundamentally, because navigating to a new path should be simpler? Navigating by anchor tags works seamlessly. Any suggestions?
before I forget: overall reitit is great, thank you for creating it! 😄
suggest getting their example code running locally, and then once you've seen it working with your own eyeballs, altering + testing it bit by bit until it's reproducing the situation you're after. somewhere along that journey, you'll find your bug!
(and you'll learn a ton along the way)
Oh should have mentioned: I already did that
When 2. didn't work I was convinced my setup was wrong so I tried the minimal example from the repository
With the setup from the respository:
(defn init-routes! []
(js/console.log "initializing routes")
(rfe/start!
router
on-navigate
{:use-fragment true}))
I can do (.pushState js/window.history nil {} "/sub-page2")
and history stack is, but when I change the init code to {:use-fragment false}
that doesn't work anymoreSome code example (from the re-frame example, commented what I added and what does not work as I would expect):
(def routes
...
["sub-page2"
{:name ::sub-page2
:view sub-page2
:link-text "Sub-page 2"}]
;; Added this route
["sub-page3/*page-path"
{:name ::sub-page3
:view sub-page3
:link-text "Sub-page 3"}]])
(def router
(rf/router
routes
{:data {:coercion rss/coercion}}))
;; Effects
(re-frame/reg-fx
:push-state
(fn [route]
(js/console.error "ROUTE" route)
(apply rfe/push-state route)))
(re-frame/reg-event-fx
::push-state
(fn [_ [_ & route]]
;; See `navigate` effect in routes.cljs
{:push-state route}))
;; ...and this handler
(re-frame/reg-event-fx
::navigate-by-path
(fn [_ [_ new-path]]
(let [match (r/match-by-path router new-path)
route-name (get-in match [:data :name])
path-params (:path-params match)]
{:fx [[:dispatch [::push-state route-name path-params]]]})))
(comment
;; This work
(re-frame/dispatch [::push-state ::sub-page2])
;; This works too
(re-frame/dispatch [::navigate-by-path "/sub-page2"])
;; This navigates but messes up the browser URL to: /sub-page3/some%2Fapp
(re-frame/dispatch [::navigate-by-path "/sub-page3/some/app"])
;; works only with {:use-fragment true}, else history stack is broken
(.pushState js/window.history nil "" "/sub-page3/some/app")
)
How can I navigate by to a catch-all route programmatically when
1. retitit.frontend.easy/push-state
does not take the path as an argument and uri encodes path-params
2. (.pushState js/window.history nil "" "/sub-page3/some/app")
only works when using fragment router and not with {:use-fragment false}
(is that a bug?)
If 2 means that calling pushState doesn't trigger Reitit-frontend on-navigate, check: https://github.com/metosin/reitit/blob/master/modules/reitit-frontend/src/reitit/frontend/history.cljs#L218-L220
I found that and tried it, but no luck 😞 But the issue I meant with 2 is that navigating back doesn't work anymore (but {:use-fragment true}
works)
Let me do a short screengrab to show what I mean
ooookay that number 2 works now: I can navigate back 😄
Then I can just manually call (-on-navigate history path)
as you indicated and I mentioned in my first message (number 3).
Here is a short clip what my initial stumbling block was: retitit.frontend.easy/push-state
uses match-by-name!
which encodes the slash while match-by-path
does not.
But I guess it doesn't make sense how I wanted to do it: I matched by path on the router to get the new route and used that to call push-state
which itself does again search for the matched route by using match-by-name.
I go the number 2 route and pushState plus -on-navigate myself (again... was stuck trying to do that for quite some time this morning 😄 )
Worked! ...and found my error: I tried it only in the repl while having 2 browser windows open but only the one I wasn't looking at received the changes 😞
Definitely learned a lot, thanks for rubber ducking, and apologies for the time taken
Some code example (from the re-frame example, commented what I added and what does not work as I would expect):