Browse Source

fix: lazy loading shakes (#9139)

* fix: lazy loading shakes

Also, enable lazy loading on mobile

* enhance(perf): lazy load deadlines and scheduled

* enhance(perf): clean up queries when components are invisible

For queries including both ::ref and ::block.
Tienson Qin 2 years ago
parent
commit
f8178bcd9b

+ 4 - 4
src/main/frontend/components/block.cljs

@@ -2909,7 +2909,8 @@
         custom-query? (boolean (:custom-query? config))]
     (if (and (or ref? custom-query?) (not (:ref-query-child? config)))
       (ui/lazy-visible
-       (fn [] (block-container-inner state repo config block)))
+       (fn [] (block-container-inner state repo config block))
+       {:debug-id (str "block-container-ref " (:db/id block))})
       (block-container-inner state repo config block))))
 
 (defn divide-lists
@@ -3337,7 +3338,7 @@
                    "More"
 
                    @*loading?
-                   (ui/lazy-loading-placeholder)
+                   (ui/lazy-loading-placeholder 88)
 
                    :else
                    "")})]))))
@@ -3429,8 +3430,7 @@
                        (rum/with-key
                          (breadcrumb-with-container blocks (assoc config :top-level? top-level?))
                          (:db/id parent)))))
-                 {:debug-id page
-                  :trigger-once? false})])))))]
+                 {:debug-id page})])))))]
 
      (and (:ref? config) (:group-by-page? config))
      [:div.flex.flex-col

+ 1 - 2
src/main/frontend/components/journal.cljs

@@ -59,8 +59,7 @@
         (blocks-cp repo page)
         (ui/lazy-visible
          (fn [] (blocks-cp repo page))
-         {:trigger-once? false
-          :debug-id (str "journal-blocks " page)}))
+         {:debug-id (str "journal-blocks " page)}))
 
       {})
 

+ 1 - 2
src/main/frontend/components/query.cljs

@@ -253,5 +253,4 @@
    (ui/lazy-visible
     (fn []
       (custom-query* config q (::query-triggered? state)))
-    {:debug-id q
-     :trigger-once? false})))
+    {:debug-id q})))

+ 7 - 1
src/main/frontend/components/scheduled_deadlines.cljs

@@ -16,7 +16,7 @@
        (not (true? (state/scheduled-deadlines-disabled?)))
        (= (string/lower-case page-name) (string/lower-case (date/journal-name)))))
 
-(rum/defc scheduled-and-deadlines < rum/reactive db-mixins/query
+(rum/defc scheduled-and-deadlines-inner < rum/reactive db-mixins/query
   [page-name]
   (let [scheduled-or-deadlines (when (scheduled-or-deadlines? page-name)
                                  (db/get-date-scheduled-or-deadlines (string/capitalize page-name)))]
@@ -33,3 +33,9 @@
                                           {})]
            (content/content page-name {:hiccup ref-hiccup}))]
         {:title-trigger? true})])))
+
+(rum/defc scheduled-and-deadlines
+  [page-name]
+  (ui/lazy-visible
+   (fn [] (scheduled-and-deadlines-inner page-name))
+   {:debug-id "scheduled-and-deadlines"}))

+ 7 - 0
src/main/frontend/db/react.cljs

@@ -51,8 +51,12 @@
 
 (defonce query-state (atom {}))
 
+;; Current dynamic component
 (def ^:dynamic *query-component*)
 
+;; Which reactive queries are triggered by the current component
+(def ^:dynamic *reactive-queries*)
+
 ;; component -> query-key
 (defonce query-components (atom {}))
 
@@ -156,11 +160,14 @@
                 transform-fn identity}} query & inputs]
   {:pre [(s/valid? ::react-query-keys k)]}
   (let [kv? (and (vector? k) (= :kv (first k)))
+        origin-key k
         k (vec (cons repo k))]
     (when-let [db (conn/get-db repo)]
       (let [result-atom (get-query-cached-result k)]
         (when-let [component *query-component*]
           (add-query-component! k component))
+        (when-let [queries *reactive-queries*]
+          (swap! queries conj origin-key))
         (if (and use-cache? result-atom)
           result-atom
           (let [{:keys [result time]} (util/with-time

+ 6 - 2
src/main/frontend/db_mixins.cljs

@@ -3,10 +3,14 @@
   (:require [frontend.db.react :as react]))
 
 (def query
-  {:wrap-render
+  {:init
+   (fn [state]
+     (assoc state :reactive-queries (atom #{})))
+   :wrap-render
    (fn [render-fn]
      (fn [state]
-       (binding [react/*query-component* (:rum/react-component state)]
+       (binding [react/*query-component* (:rum/react-component state)
+                 react/*reactive-queries* (:reactive-queries state)]
          (render-fn state))))
    :will-unmount
    (fn [state]

+ 28 - 28
src/main/frontend/ui.cljs

@@ -1065,8 +1065,8 @@
    (progress-bar width)])
 
 (rum/defc lazy-loading-placeholder
-  []
-  [:div.shadow.rounded-md.p-4.w-full.mx-auto.mb-5.fade-in {:style {:height 88}}
+  [height]
+  [:div.shadow.rounded-md.p-4.w-full.mx-auto.mb-5.fade-in {:style {:height height}}
    [:div.animate-pulse.flex.space-x-4
     [:div.flex-1.space-y-3.py-1
      [:div.h-2.bg-base-4.rounded]
@@ -1076,37 +1076,37 @@
        [:div.h-2.bg-base-4.rounded.col-span-1]]
       [:div.h-2.bg-base-4.rounded]]]]])
 
-(rum/defcs lazy-visible-inner
-  [state visible? content-fn ref]
-  [:div.lazy-visibility
-   {:ref ref
-    :style {:min-height 24}}
-   (if visible?
-     (when (fn? content-fn)
-       [:div.fade-enter
-        {:ref #(when-let [^js cls (and % (.-classList %))]
-                 (.add cls "fade-enter-active"))}
-        (content-fn)])
-     (lazy-loading-placeholder))])
+(rum/defc lazy-visible-inner
+  [visible? content-fn ref]
+  (let [[set-ref rect] (r/use-bounding-client-rect)
+        placeholder-height (or (when rect (.-height rect)) 88)]
+    [:div.lazy-visibility {:ref ref}
+     [:div {:ref set-ref}
+      (if visible?
+        (when (fn? content-fn)
+          [:div.fade-enter
+           {:ref #(when-let [^js cls (and % (.-classList %))]
+                    (.add cls "fade-enter-active"))}
+           (content-fn)])
+        (lazy-loading-placeholder placeholder-height))]]))
 
 (rum/defc lazy-visible
   ([content-fn]
    (lazy-visible content-fn nil))
   ([content-fn {:keys [trigger-once? _debug-id]
-                :or {trigger-once? true}}]
-   (if (or (util/mobile?) (mobile-util/native-platform?))
-     (content-fn)
-     (let [[visible? set-visible!] (rum/use-state false)
-           inViewState (useInView #js {:rootMargin "100px"
-                                       :triggerOnce trigger-once?
-                                       :onChange (fn [in-view? entry]
-                                                   (let [self-top (.-top (.-boundingClientRect entry))]
-                                                     (when (or (and (not visible?) in-view?)
-                                                               ;; hide only the components below the current top for better ux
-                                                               (and visible? (not in-view?) (> self-top 0)))
-                                                       (set-visible! in-view?))))})
-           ref (.-ref inViewState)]
-       (lazy-visible-inner visible? content-fn ref)))))
+                :or {trigger-once? false}}]
+   (let [[visible? set-visible!] (rum/use-state false)
+         root-margin 100
+         inViewState (useInView #js {:rootMargin (str root-margin "px")
+                                     :triggerOnce trigger-once?
+                                     :onChange (fn [in-view? entry]
+                                                 (let [self-top (.-top (.-boundingClientRect entry))]
+                                                   (when (or (and (not visible?) in-view?)
+                                                             ;; hide only the components below the current top for better ux
+                                                             (and visible? (not in-view?) (> self-top root-margin)))
+                                                     (set-visible! in-view?))))})
+         ref (.-ref inViewState)]
+     (lazy-visible-inner visible? content-fn ref))))
 
 (rum/defc portal
   ([children]