Skip to content

Instantly share code, notes, and snippets.

@geraldodev
Last active June 21, 2022 13:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save geraldodev/144ac42fca696431991f46b42c6f5149 to your computer and use it in GitHub Desktop.
Save geraldodev/144ac42fca696431991f46b42c6f5149 to your computer and use it in GitHub Desktop.
https://github.com/TanStack/virtual rowVirtualizer helix snippet
(ns crudis.ui.root
(:require
["@tanstack/react-virtual" :refer [useVirtualizer]]
["react" :as React]
[goog.object :as gobj]
[helix.core :as hx :refer [defnc $ <> fnc]]
[helix.dom :as d :refer [div a button]]
[helix.hooks :as hooks :refer [use-state]]
[paqueta.fetch :as fetch] ;; lambdaisland fetch
))
(defnc EmployeesView
[]
(let [[employees set-employees] (hooks/use-state nil)
get-item #(aget employees %) ;; employess is a js vec
;; this is the key. you need to pass a ref to store the current position of the row virtualizer
employee-list-ref (React/useRef)
^js rowVirtualizer (useVirtualizer #js {:count (count employees) ;; count based on the current fetched employees
;; a function to return the current position
:getScrollElement #(gobj/get employee-list-ref "current")
;; the estimate size of the item. It could be dynamic, but in this case it's fixed, in px
:estimateSize (constantly 30)
;; the number of rows that'll be computed by the virtualizer beyond what is being watched
;; in order to avoid momentary blank items
:overscan 3
;; you can provide a item key factory. that would be usefull if you want keys
;; with meaningfull data
;; i've put the console.log here to understand when this function is called
;; when you provide it. its called for all items of the index (based on the count)
;; note that calling this function just computes the key, it does not render
;; the items
; :getItemKey (fn [index]
; ; (js/console.log "getItemKey"
; ; (count employees)
; ; index)
; (gobj/get (get-item index)
; "employee_id"))
})]
(hooks/use-effect
:once
(p/let [resp (fetch/get "/api/employees"
{:accept :json
:content-type :json})]
(when (= (:status resp) 200)
(let [b (:body resp)]
(when (not= b employees)
(set-employees b))))))
(div
{:class "px-2"}
"EmployeesView"
(div
{:class "space-x-4"}
;; here is the div that will be "row virtualized"
;; with this library you have to provide your own style which I think it's awesome.
;; look the super important ref as a parent of the inner div
;; overflow auto is to enable scrolling
(div
{:ref employee-list-ref
:style {:height "100px"
:width "300px"
:overflow "auto"}}
;; an inner div whose the height is the totalSize of the virtualizer
;; the position needs to be relative to anchor the items. the items needs to be position absolute
(div {:style {:height (str (.getTotalSize rowVirtualizer) "px")
:width "100%"
:position "relative"}}
; (js/console.log (count (.getVirtualItems rowVirtualizer)))
;; virtual items
(for [vi (.getVirtualItems rowVirtualizer)]
;; lookup the employee by index of the virtual item
(let [employee (get-item (.-index vi))]
; (js/console.log employee)
(div
{:key (.-index vi) ;; key to keep react happy
;; these items will be anchored on the position: relative parent
:style {:position "absolute"
:top 0
:left 0
:width "100%"
:height (str (.-size vi) "px")
:transform (str "translateY(" (.-start vi) "px)")}} ;; css trickery to position absolute Y axis
(str "idx " (.-index vi)
" key " (.-key vi) " "
(gobj/get employee "first_name")))))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment