Browse Source

enhance: perf improvement for long pages

Tienson Qin 4 years ago
parent
commit
01fec95ef6
3 changed files with 70 additions and 22 deletions
  1. 48 16
      src/main/frontend/components/block.cljs
  2. 1 1
      src/main/frontend/ui.cljs
  3. 21 5
      src/main/frontend/util.cljc

+ 48 - 16
src/main/frontend/components/block.cljs

@@ -76,11 +76,8 @@
   (atom nil))
 (def *move-to (atom nil))
 
-;; TODO: Improve blocks grouped by pages
-(defonce max-blocks-per-page 500)
-(defonce virtual-list-scroll-step 450)
-(defonce virtual-list-previous 50)
-
+;; TODO: dynamic
+(defonce max-blocks-per-page 200)
 (defonce *blocks-container-id (atom 0))
 
 ;; TODO:
@@ -2478,6 +2475,51 @@
                      blocks)]
        sections))))
 
+(defn- block-list
+  [config blocks]
+  (for [[idx item] (medley/indexed blocks)]
+    (let [item (->
+                (dissoc item :block/meta)
+                (assoc :block/top? (zero? idx)
+                       :block/bottom? (= (count blocks) (inc idx))))
+          config (assoc config :block/uuid (:block/uuid item))]
+      (rum/with-key
+        (block-container config item)
+        (:block/uuid item)))))
+
+(defonce ignore-scroll? (atom false))
+(rum/defcs lazy-blocks <
+  (rum/local 1 ::page)
+  [state config blocks]
+  (let [*page (get state ::page)
+        segment (->> blocks
+                    (drop (* (dec @*page) max-blocks-per-page))
+                    (take max-blocks-per-page))
+        bottom-reached (fn []
+                         (when (and (= (count segment) max-blocks-per-page)
+                                    (> (count blocks) (* @*page max-blocks-per-page))
+                                    (not @ignore-scroll?))
+                           (swap! *page inc)
+                           (util/scroll-to-top))
+                         (reset! ignore-scroll? false))
+        top-reached (fn []
+                      (when (> @*page 1)
+                        (swap! *page dec)
+                        (reset! ignore-scroll? true)
+                        (js/setTimeout #(util/scroll-to
+                                         (.-scrollHeight (js/document.getElementById "lazy-blocks"))) 100)))]
+    [:div#lazy-blocks
+     (when (> @*page 1)
+       [:div.ml-4.mb-4 [:a#prev.opacity-60.opacity-100.text-sm.font-medium {:on-click top-reached}
+                        "Prev"]])
+     (ui/infinite-list
+      "main-container"
+      (block-list config segment)
+      {:on-load bottom-reached})
+     (when (> (count blocks) (* @*page max-blocks-per-page))
+       [:div.ml-4.mt-4 [:a#more.opacity-60.opacity-100.text-sm.font-medium {:on-click bottom-reached}
+                        "More"]])]))
+
 (rum/defcs blocks-container <
   {:init (fn [state]
            (assoc state ::init-blocks-container-id (atom nil)))}
@@ -2504,17 +2546,7 @@
                                0
                                :else
                                -10)}}
-       (let [first-block (first blocks)
-             first-id (:block/uuid (first blocks))]
-         (for [[idx item] (medley/indexed blocks)]
-           (let [item (->
-                       (dissoc item :block/meta)
-                       (assoc :block/top? (zero? idx)
-                              :block/bottom? (= (count blocks) (inc idx))))
-                 config (assoc config :block/uuid (:block/uuid item))]
-             (rum/with-key
-               (block-container config item)
-               (:block/uuid item)))))])))
+       (lazy-blocks config blocks)])))
 
 ;; headers to hiccup
 (defn ->hiccup

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

@@ -347,7 +347,7 @@
 (rum/defcs infinite-list <
   (mixins/event-mixin attach-listeners)
   "Render an infinite list."
-  [state list-element-id body {:keys [on-load has-more]}]
+  [state list-element-id body {:keys [on-load has-more on-top-reached]}]
   (rum/with-context [[t] i18n/*tongue-context*]
     (rum/fragment
      body

+ 21 - 5
src/main/frontend/util.cljc

@@ -395,6 +395,15 @@
                                   (- top 80)))
                          :behavior "smooth"}))))))
 
+#?(:cljs
+   (defn scroll-to-element-v2
+     [elem-id]
+     (when elem-id
+       (when-let [elem (gdom/getElement elem-id)]
+         (.scroll (app-scroll-container-node)
+                  #js {:top (element-top elem 0)
+                       :behavior "auto"})))))
+
 #?(:cljs
    (defn scroll-to
      ([pos]
@@ -407,11 +416,6 @@
                  #js {:top      pos
                       :behavior (if animate? "smooth" "auto")})))))
 
-#?(:cljs
-   (defn scroll-to-top
-     []
-     (scroll-to (app-scroll-container-node) 0 false)))
-
 #?(:cljs
    (defn scroll-top
      "Returns the scroll top position of the `node`. If `node` is not specified,
@@ -421,6 +425,18 @@
      ([node]
       (when node (.-scrollTop node)))))
 
+#?(:cljs
+   (defn scroll-to-top
+     []
+     (scroll-to (app-scroll-container-node) 0 false)))
+
+#?(:cljs
+   (defn scroll-to-bottom
+     [node]
+     (when-let [node ^js (or node (app-scroll-container-node))]
+       (let [bottom (.-scrollHeight node)]
+         (scroll-to node bottom false)))))
+
 (defn url-encode
   [string]
   #?(:cljs (some-> string str (js/encodeURIComponent) (.replace "+" "%20"))))