Skip to content

Home: Hints on Using Fulcro and Fulcro RAD

realgenekim edited this page Oct 5, 2024 · 2 revisions

Making a component that takes parameters from a route

Problem

I want to pass a :video/id (for a Vimeo video) to this component, but no matter how I route to it, :video/id is always nil?

(defsc VideoPlayerMinimum [this {:video/keys [id] :as props}]
  {:query [:video/id]
   :ident (fn [] [:component/id ::VideoPlayerMinimum])
   :route-segment ["video-player-min"]
   :initial-state {:video/id nil}}
  (dom/div
    (dom/p "Props: " (str props))
    (if id
      (dom/p "Video ID: " (str id))
      (dom/p "No video ID provided"))))

Here’s how I’m routing to it:

(rroute/route-to! this video-player/VideoPlayerMinimum {:video/id "hello"})

And here's what I see —- what I expect is for this component it render “hello,” not nil or a blank string.

image

Answer

The reason it doesn't work is that the component is missing the tools to participate in the dynamic routing system. The code should look like this:

(ns com.example.ui.video-player
  (:require
    [com.example.ui.util.viewers :as viewers]
    [com.example.impl.vimeo :as impl-vimeo]
    #?(:clj  [com.fulcrologic.fulcro.dom-server :as dom :refer [div label input]]
       :cljs [com.fulcrologic.fulcro.dom :as dom :refer [div label input]])
   [com.fulcrologic.fulcro.algorithms.merge :as merge]
   [com.fulcrologic.fulcro.components :as comp :refer [defsc]]
   [com.fulcrologic.fulcro.mutations :as m]
   #?(:cljs [com.fulcrologic.fulcro.dom :as dom :refer [div p button iframe]])
   [com.fulcrologic.fulcro.routing.dynamic-routing :as dr]
   #?(:cljs [goog.events :as events])
   [taoensso.timbre :as log]))

(defsc VideoPlayerMinimum [this {:video/keys [id] :as props}]
  {:query [:video/id]
   :ident (fn [] [:component/id ::VideoPlayerMinimum])
   :route-segment ["video-player-min"]
   :initial-state {:video/id nil}
   :will-enter (fn [app {:video/keys [id]}]
                 (dr/route-deferred [:component/id ::VideoPlayerMinimum]
                   (fn []
                     (merge/merge-component! app VideoPlayerMinimum {:video/id id})
                     (dr/target-ready! app [:component/id ::VideoPlayerMinimum]))))}
  (dom/div
    (dom/p "Props: " (str props))
    (if id
      (dom/p "Video ID: " (str id))
      (dom/p "No video ID provided"))))

image

As Claude 3.5 Sonnet explains:

The :will-enter option is used in the VideoPlayerMinimum component for dynamic routing purposes. Here's an explanation of why it's necessary:

  1. Dynamic Routing: In Fulcro, :will-enter is part of the dynamic routing system. It's used to handle route transitions and prepare the component before it's rendered.

  2. Deferred Route Resolution: The dr/route-deferred function is used to indicate that the route resolution might not be immediate. This is useful when you need to fetch data or perform some asynchronous operation before the component is ready to be displayed. Data Merging: Inside the deferred function, merge/merge-component! is used to merge the video ID into the app state for this component. This ensures that the component has the necessary data before it's rendered.

  3. Route Readiness: The dr/target-ready! call signals that the component is ready to be rendered. This is important in dynamic routing to ensure that the UI doesn't update until all necessary data and preparations are complete.

  4. Handling URL Parameters: The :will-enter function receives the app and any route parameters. In this case, it's expecting a :video/id parameter, which could be passed through the URL.

  5. Initialization: This approach allows the component to initialize its state based on route parameters, which is particularly useful for components that depend on data from the URL or need to fetch data based on route parameters.

By using :will-enter, you ensure that the VideoPlayerMinimum component is properly initialized with the correct video ID from the route before it's rendered, providing a smoother user experience and avoiding potential issues with missing data.

Thank you, @sheluchin, @janezj!

Source: https://clojurians.slack.com/archives/C68M60S4F/p1727206228722579

Clone this wiki locally