Skip to content

A Fable.React hook that determines whether a component is currently visible on the screen.

License

Notifications You must be signed in to change notification settings

JordanMarr/Feliz.UseIsVisible

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Feliz.UseIsVisible

A Fable.React hook that determines whether a component is currently visible on the screen.

Installation

Get it from NuGet!

NuGet version (Feliz.UseIsVisible)

Usage

This hook is useful when you need to display a large amount and you only want to render rows that are visible on the screen for performance reasons.

Example

In this example, 5000 rows are displayed, and the (vertical) margin is set to 400px (which extends the "visible" range above and below the visible screen):

useIsVisible400

Code

This approach requires that your dynamically rendered row be broken out into its own component that utilizes the useIsVisible hook:

open Feliz
open Feliz.UseIsVisible

Using Feliz DSL

[<ReactComponent>]
let Row (entry: Monthly.EntryView) = 
    let rowRef = React.useElementRef()
    let isVisible = React.useIsVisible(rowRef, margin = 400, dependencies = [||])

    if isVisible then
        Html.tr [
            prop.ref rowRef
            prop.children [
                Html.td [ str entry.Username ]
                Html.td [ str (entry.Date.ToString("M/d/yyyy")) ]
                Html.td [ str entry.Task ]
                Html.td [ str (entry.Hours.ToString("0.00")) ]
                Html.td [ str entry.Project ]
                Html.td [ str entry.Email ]
                Html.td [ str "8:00 AM" ]
            ]
        ]
    else
        Html.tr [
            prop.ref rowRef            
            prop.children [
                Html.td [
                    prop.colSpan 7
                    prop.children [
                        Html.b [
                            str "Loading..."
                        ]
                    ]
                ]
            ]
        ]

Using Fable.React DSL

[<ReactComponent>]
let Row (entry: Monthly.EntryView) = 
    let rowRef = React.useElementRef()
    let isVisible = React.useIsVisible(rowRef, margin = 400, dependencies = [||])

    if isVisible then
        tr [ Ref (adaptFelizUseElementRef rowRef) ] [
            td [] [ str entry.Username ]
            td [] [ str (entry.Date.ToString("M/d/yyyy")) ]
            td [] [ str entry.Task ]
            td [] [ str (entry.Hours.ToString("0.00")) ]
            td [] [ str entry.Project ]
            td [] [ str entry.Email ]
            td [] [ str "8:00 AM" ]
        ]
    else
        tr [ Ref (adaptFelizUseElementRef rowRef) ] [
            td [ ColSpan 7 ] [
                b [] [ str "Loading..." ]
            ]
        ]

The Entire Code

module HoursWorkedPage

open System
open Feliz
open Fable.React
open Fable.React.Props
open Feliz.UseIsVisible

[<ReactComponent>]
let Row (entry: Monthly.EntryView) = 
    let rowRef = React.useElementRef()
    let isVisible = React.useIsVisible(rowRef, margin = 400)

    if isVisible then
        tr [ Ref (adaptFelizUseElementRef rowRef) ] [
            td [] [ str entry.Username ]
            td [] [ str (entry.Date.ToString("M/d/yyyy")) ]
            td [] [ str entry.Task ]
            td [] [ str (entry.Hours.ToString("0.00")) ]
            td [] [ str entry.Project ]
            td [] [ str entry.Email ]
            td [] [ str "8:00 AM" ]
        ]
    else
        tr [ Ref (adaptFelizUseElementRef rowRef) ] [
            td [ ColSpan 7 ] [
                b [] [ str "Loading..." ]
            ]
        ]

[<ReactComponent>]
let Page (company: Company) =
    let entries, setEntries = React.useState<Monthly.EntryView array>(Array.empty)
    
    React.useEffectOnce(fun () ->
        [|
            for n in [1 .. 5000] do
                {
                    EntryView.Date = DateTime.Today
                    EntryView.Email = "person@email.com"
                    EntryView.Hours = 8
                    EntryView.Project = $"Project %i{n}"
                    EntryView.Task = $"Task %i{n}"
                    EntryView.Username = $"User %i{n}"
                }
        |]
        |> setEntries
    )

    let export() = 
        printfn "Exporting..."

    Ctrls.container [
        h4 [] [str "Hours Worked"]

        Ctrls.row [
            div [Class "col text-right"] [
                Button.commandBarButton [Button.IconProps {| iconName = "ExcelDocument" |}; Button.Title "Download Excel"; Button.OnClick (fun e -> export())] [
                    str "Export to Excel"
                ]                    
            ]
        ]
        Ctrls.row [
            Ctrls.col [
                table [Id "monthly-tbl"; Class "table"] [
                    thead [] [
                        tr [] [
                            th [Style [Width "100px"]] [str "BIM Detailer"]
                            th [Style [Width "70px"]] [str "Date"]
                            th [Style [Width "150px"]] [str "Task"]
                            th [Style [Width "70px"]] [str "Hours"]
                            th [Style [Width "150px"]] [str "Project"]
                            th [Style [Width "100px"]] [str "Email Address"]
                            th [Style [Width "100px"]] [str "Start Time"]
                        ]
                    ]
                    tbody [] [
                        for e in entries do
                            Row e
                    ]
                ]
            ]
        ]
    ]

Optional Parameters

  • margin allows you to specify a margin (in pixels) above and below the visible screen that will extend the "visible" region.
  • dependencies allows you to pass in an obj[] of dependencies that will trigger useIsVisible to refresh if any of the dependency values change.

About

A Fable.React hook that determines whether a component is currently visible on the screen.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages