How do you accomplish SPA re-frame teardown?

Building Reitit SPA, frequently it is desirable to do tear-down to delete state after leaving a page. We use Reitit Front-end and the controller :stop keyword is billed as the solution, but it seems to be broken. How do you manage this?

Does anybody do tear-down on their Re-Frame SPAs?

I’m not familiar with Reitit, but I’ve used these with re-frame/reagent:

  • react lifecycle methods; componentWillUnmount - this is good for when a specific page has special requirements
  • In the re-frame handler for page navigation - this is good when all/most pages have the same requirements.
1 Like

Thank you! The :component-did-unmount should work perfectly!

Sorry I never wrote back, but I actually checked with my reitit-frontend-using web app template to see if I was seeing calls to stop and start controllers, and I do. It is not re-frame, so you won’t see the tearing down of components, but you can see a working example of reitit controllers.

I have made a tiny project to demonstrate the start and stop controllers based on the template here. The readme describes how to start the example. :slight_smile:

1 Like

Thank you! I also received a response on the Reitit issue, so together with your example I should be abl to make it work.

Solution achieved, :stop working! The key was to take my controller call out of the routes operator and instead put it in the re-frame event. Solution:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; REITIT-FRONTEND ROUTES ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(ns centrifuge.routes
  (:require [reitit.frontend :as rf]
            [reitit.frontend.easy :as rfe]            
            [re-frame.core :as rfc]
            ;; [reitit.coercion :as rc]
            ;; [reitit.coercion.schema :as rsc]
            [centrifuge.views.dashboard :as dash]
            [centrifuge.views.article :as article]
            [centrifuge.views.admin :as admin]))

(def routes
  (rf/router
   ["/"
    [""
     {:name ::front-dashboard
      :view #'dash/home-page}]
    ["article/:id"
     {:name ::article
      :view #'article/main-page
      :controllers [{:parameters {:path [:id]}
                     :start (fn [p] (rfc/dispatch [:set-current-article
                                                   (or (-> p :path :id)
                                                       "NOT FOUND")]))
                     :stop (fn [_] (do
                                     (println "Running stop!")
                                     (rfc/dispatch [:set-current-article nil])))}]}]]))

(defn init-routes!
  "Start the routing"
  []
  (rfe/start! routes
              (fn [m]
                (rfc/dispatch [:set-current-page m]))
              {:use-fragment false}))

;;;;;;;;;;;;;;;
;; NEXT FILE ;;
;;;;;;;;;;;;;;;
(ns centrifuge.events
  (:require 
   ;; ... 
   [reitit.frontend.controllers :as rfcontrol]
   ;; ...
   ))

(rfc/reg-event-db
 :set-current-page
 (validate-spec ::db/app-db)
 (fn [db [_ m]]
   (let [prev-match (:current-page db)
         controlled (assoc m :controllers (rfcontrol/apply-controllers (:controllers prev-match) m)) ]
     (assoc db :current-page controlled))))
1 Like

I am happy you got it working. :grinning: