Graphic details page
Making graphic list items clickable; and the editor(detail) route. In the process, we'll learn how to use React's Higher Order Components with Reagent.
With the graphics list in place, we will now build the details page for each graphic. The details page will include an editor component that will let us draw the actual graphic. In this chapter, we'll focus on the routing aspect and not concern ourselves with the actual editor.

Parsing route params#
React Router provides various mechanisms to parse route params (:graphicId
in our case). There is a higher-order-component (HOC)-based approach using withRouter
HOC, and a hooks-based approach using the useParams
hook. We are going to use the withRouter
HOC in our app.
The withRouter
HOC expects a React component as an argument. One small issue - ratoms don't work with React! However ratoms do work as children of React components. The solution is to create a transparent wrapper to the desired Reagent component and pass in the props manually. Then reactify this wrapper component, so ratoms continue to work. Let's understand this with an example:
(def counter-atom (r/atom nil))
;; reagent component that needs route props and depends on ratoms
(defn x-page [props]
(let [counter @counter-atom]
;;
))
;; container component that will be reactified
(defn x-page-container [props]
[x-page props])
;; somewhere in the router
[:> Route {:to "/g/:id"}
[:> (withRouter (r/reactify-component x-page-container))]]
Now x-page-container
is reactified and cannot use ratoms, however, its children can safely use ratoms.
Graphics page Switch
#
The details for a graphic will be available at /graphics/:graphicId
route. As per our app structure, the namespace responsible for this route is app.pages.graphics.detail
.
We will also need an additional Switch
component in app.pages.graphics
since we need to compose routes as follows:

Let's update our app.pages.graphics
namespace to accommodate this Switch
:
(defn list-component []
[:<>
[nav/top]
[:div {:class "w-100 md:w-2/3 m-auto p-4"}
[header]
[graphics-list]
]])
(defn graphics-detail-container [props]
[detail/page props])
(defn page []
[auth/private
[:> Switch
[:> Route {:path "/graphics" :exact true} [list-component]]
[:> Route {:path "/graphics/:graphicId" :exact true}
[:> (withRouter (r/reactify-component graphics-detail-container))]]]])
we extracted the existing
page
component tolist-component
replaced
page
with aSwitch
when the route
path
is/graphics
thelist-component
will be renderedwhen the route
path
is/graphics/:graphicId
, thegraphics-detail-container
will be reactified and rendered. It will also receive route properties courtesy ofwithRouter
HOC.graphics-detail-container
internally renders thedetail/page
component, which we haven't created yetthe
exact
prop prevents thelist
component from being rendered on/graphics/:graphicId
. It's how React Router composes.
Link graphic card#
The graphic-card
component should redirect the user to /graphics/:graphicId
when the card is clicked. We can achieve this by using React Router's Link
component.
Let's update our card and wrap its content in a Link
: