Fork me on GitHub
#reitit
<
2019-04-20
>
valtteri06:04:08

Cool! I was also thinking that I could spin up a small re-frame example as well.

Francesco20:04:17

nice Valtteri, thanks! I really like that you thought of Link, NavLink and Redirect (since then it’s easy to re-use within components). I have one question, what about the re-frame example? does navigation need to be tight to the db/global state? instead, what is your opinion regarding this approach: https://gist.github.com/cdbkr/2bfe679df32e7226ab1909d2a1bebf46

valtteri06:04:40

Thanks for the feedback @UHBF7CA3V! Regarding your question, do you mean this part

(defn main-panel []
  (let [current-route (re-frame/subscribe [::subs/current-route])]
    [:div
     [nav]
     (condp = (-> @current-route :data :name)
       ::routes/home      [home-page]
       ::routes/sub-page1 [sub-page1]
       ::routes/sub-page2 [sub-page2]
       [:div
        [:p (str "Unknown page")]
        [:pre @current-route]])]))
..would be implemented similarly to the gist where each route knows all the views associated with it? That could definitely be done quite trivially. Do you think it would be simpler that way?

Francesco08:04:40

thanks Valtteri! yes, I am referring to that part. I don’t have any real experience with re-frame so my point might be wrong. as a FE developer, I’d leave management of routes to the router only (and I really like how Reitit does it - and what Juho demonstrated with the nested views approach). I think it would be easier to understand and to manage but I am not sure if it would be against the “re-frame” approach. One thing I see though it’s the approach you suggest might be combined with interceptors and events fetching external data. (would it be a really bad practice firing the event in the router controller or - yes - in the componendDidMount function and subscribe to db/state changes inside the same component?)

valtteri09:04:27

This is an interesting topic! I see the point in keeping all following responsibilities within the reouter: - which view to render - keep browser address bar in sync - what code to run when the view changes I’m not sure if there would be problems with re-frame. I could give it a spin tonight or tomorrow night and see how it goes. 🙂

valtteri09:04:35

I think that controllers are proper place to trigger “init” code/side-effects that are related to view changing

valtteri09:04:54

Definitely better than componentDidMount.

Francesco09:04:40

exactly, that’s discussing the same topic, although, referring to that article, I am not convinced about coupling/tangling db events with navigation events (it seems lots of things coupled together). so I agree with you, maybe controllers would be a better place for triggering side-effects (within this context).

valtteri09:04:47

Yeah, it makes more sense when you think routing as a “user intention”. I mean, something such as “When I navigate to http://foo.com/profile I’m expecting to see my profile data there”. There is actually quite many things tangled into that routing “event”.

valtteri10:04:10

So there probably needs to be an orchestrator of some sort who is in charge of all that.. And the router could very well be that orchestrator because it’s quite central to what’s going on there.

Francesco10:04:25

Totally agree, my concern is with creating new events just for navigation and polluting the app “db” with that implementation... I think the router is already doing that and composing the views, it allows also some triggering when a route is mounting/mounted

valtteri10:04:21

Yeah, the re-frame way is that events (and events only) cause side-effects.. So if something needs to change the route programmatically, it’d go event->effect->changes-in-world->subscriptions->view. App-db is used only for storing the “current route” in case some component/view wants to know that, they can easily subscribe to it. It may be redundant if views are composed like in the gist and the Router component passes down its state to the views.

valtteri10:04:46

So I guess the question is whether it’s good or bad to have Router state (or parts of it) in the app-db.

valtteri11:04:32

In Re-frame I think the app-db is the correct place. Anything that affects how a view is going to be rendered should come from the state and the the single source of truth for state should be the app-db.

valtteri11:04:43

(I’m writing down my thought process.. Sorry for the noise) 🙂

Francesco11:04:02

thanks for your explanations and thoughts 🙂 in the react/redux world, there is also this concept https://reacttraining.com/react-router/web/guides/redux-integration

valtteri11:04:24

Yeah I’ve never used Redux but AFAIK it’s pretty much the same pattern as re-frame..? It could be a good idea to also have a ‘Redux’ example.

valtteri11:04:12

Good points in the redux-integration guide 👍

valtteri11:04:57

I guess it boils down to whether to pass the router state as props vs. subscribing from the app-db.

Francesco11:04:58

yeah, it’s almost a similar pattern (re-frame - redux). storing the routing details the router is discouraged though (there are few reasons on that page), but it’s still possible, so the example is mirroring that pattern

Francesco11:04:14

maybe passing router state as props is more “pure” (so components tree reacts based on that)…but both solutions are valid

valtteri11:04:12

AFAIK there’s no consensus in re-frame which one is ‘better’. I tend to have both type of components for different situations.

valtteri11:04:35

What are your thoughts about the example? Should we present both ways?

valtteri11:04:16

RE: about the component tree thing; If a component subscribes to state in app-db, re-frame triggers re-render for all the subscribers if the subscribed data changes. So it’s effectively the same as passing props

Francesco11:04:56

The only way I have used route navigation with redux (or a similar state management solution) was with react-native (in order to handle differences between platforms), so I am trying to understand why so many examples with re-frame (also rum) are considering that approach, instead of relying only on something like Link NavigationLink based on a Router solution. at this time, I think that both ways might help

Francesco11:04:36

absolutely, that’s a valid point too

Francesco11:04:21

though with props is more about a top-down thingy…meanwhile I am thinking of two components in the tree subscribing to the same data :thinking_face:

valtteri11:04:45

I tend to have “container components” that subscribe to some data and pass it down as props to pure components.

Francesco11:04:10

agree, I like that approach too

valtteri16:04:45

Here’s second take on re-frame example flattened into single file so it goes nicely into a gist: https://gist.github.com/vharmain/a8bbfa5bc601feba0f421959228139a1

🔝 4
👍 4
valtteri07:04:03

I updated the PR with this approach 👍

Francesco07:04:15

thanks Valtteri, it looks great and super helpful 🙂

valtteri07:04:44

Thank you for the feedback and ideas!

lilactown21:04:39

very frustrated. 1. I have a spec (s/def ::rules (s/coll-of keyword?)) I'm using with reitit.coercion.spec. Changing it to (s/def ::rules (s/and (comp not empty?) (s/coll-of keyword?))) results in some sort of assertion error when I send a request to the endpoint

lilactown21:04:51

2. I can't seem to find any way to actually understand what this error is.

lilactown21:04:21

I receive no stack trace in my process, nor does the response from the service illuminate anything

lilactown21:04:26

{
  "type": "exception",
  "class": "java.lang.AssertionError"
}

lilactown21:04:48

it is occurring before my handler and I have no idea how to get reitit to log errors before it reaches the handler for that route

lilactown21:04:51

sigh and it looks like this no longer occurs in 0.3.1. I was on 0.2.9

ikitommi22:04:32

my slides from Clojure/North: https://www.slideshare.net/metosin/reitit-clojurenorth-2019-141438093

💯 8
parrot 4
👍 20
✌️ 4
📈 4