Reagent/routing/SPA question

794 views
Skip to first unread message

Jonathon McKitrick

unread,
Apr 22, 2017, 1:13:33 PM4/22/17
to ClojureScript
I have an app that's been working wonderfully for a few years now. I want to improve it by adding links. If you see a person's name, I want to be able to click on that name and the app will jump to the 'user' page (simple enough) and then move the browser view to that particular item. In static HTML we'd obviously do that with a # and an anchor. But with Reagent, I'm not quite sure.

I'm exploring Secretary right now, but what's the missing piece that will get me from a link to a Reagent-rendered page and then jumping to that row or even opening a modal with that item?

Torsten Uhlmann

unread,
Apr 25, 2017, 3:32:14 AM4/25/17
to ClojureScript
There are a few other client side routing libraries that support bidirectional linking. One of them is Bidi (https://github.com/juxt/bidi) on their README there's a list of possible alternatives.

In my app I'm using a combination of Secretary with some parts of Accountant (https://github.com/venantius/accountant), in order to navigate between routes without reloading the page. There's a blog post here that may help: https://pez.github.io/2016/03/01/Reagent-clientside-routing-with-Bidi-and-Accountant.html

For me, to be able to generate the link from a route, I used Secretary's "named routes" feature

So, in order to get a link I do something like:

#(site/detail-entry-route {:detailEntryId (.toString (:_id %))})

which returns the link to some detail url.

And the Secretary part looks like:

(secretary/defroute detail-entry-route "/detail-entry/:detailEntryId"
[timerollEntryId]
(session/put! :current-page :detail-page)
(session/put! :selected-item-id detailEntryId))

In Secretary the feature is called "named routes": https://github.com/gf3/secretary#named-routes

Hope that helps,
Torsten.

Jonathan Fischer

unread,
Apr 26, 2017, 1:40:40 AM4/26/17
to ClojureScript
It kind of comes down to how you're managing the state in your project. I'm using re-frame at the moment, so I have kind of top-level key in my project state to tell me what the user's looking at. Then I register my routes with Secretary and each route just kicks off an event that'll eventually modify that top-level key.

So more specifically, my project's state is in one big map, and I have a key `:app/view` that has a view id I can use to figure out what to render, along with any additional info it might need.

(def default-db
{:app/view {:view/id :view/sign-in}})

My routing code looks like this (I only start listening to navigation events after a user has signed in, and stop again when she signs out):

(ns my-app.routing
(:require-macros [secretary.core :refer [defroute]])
(:require [re-frame.core :refer [console dispatch]]
[goog.events :as events]
[secretary.core :as secretary])
(:import [goog.history Html5History]))

(defonce history
(let [h (Html5History.)]
(events/listen h
goog.history.EventType.NAVIGATE
(fn [e]
(when (.-isNavigation e)
(secretary/dispatch! (.-token e)))))
h))

(defn set-token! [token]
(.setToken history token))

(defn get-token
"Returns the current history token (e.g. the stuff after the # in the URL)"
[]
(.getToken history))

(defn listen!
"Starts listening for and dispatching history/navigation events."
[]
(.setEnabled history true))

(defn stop!
"Stops listening for navigation events."
[]
(.setEnabled history false))

(defroute "/data-logging" []
(dispatch [:events/navigate {:view/id :view/data-logging}]))

(defroute "/info" []
(dispatch [:events/navigate {:view/id :view/info}]))

(defroute #"/page/(\d+)"
[page-id]
(dispatch [:events/navigate {:view/id :view/page :page/id (js/parseInt page-id)}]))

(defroute "*"
;; Catch-all history token router to show a 404 page, etc.
{:as params}
(dispatch [:events/navigate {:view/id :view/unknown}]))

Again, using re-frame, so I dispatch an event and handle it elsewhere, but that navigate event just ends up modifying the :app/view key, something like:

(swap! app-state #(assoc % :app/view new-value))

Where app-state is a Reagent atom and updating it triggers a re-render.

jmcki...@gmail.com

unread,
Apr 30, 2017, 5:03:52 PM4/30/17
to ClojureScript
Ok, I’ll have to dig into your examples and code and see which approach I’ll try.

--
Note that posts from new members are moderated - please be patient with your first post.
---
You received this message because you are subscribed to a topic in the Google Groups "ClojureScript" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojurescript/7S4axBtK8Pg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojurescrip...@googlegroups.com.
To post to this group, send email to clojur...@googlegroups.com.
Visit this group at https://groups.google.com/group/clojurescript.
--
Jonathon McKitrick
Reply all
Reply to author
Forward
0 new messages