5

GitHub - JordanMarr/Feliz.UseIsVisible: A Fable.React hook that determines wheth...

 2 years ago
source link: https://github.com/JordanMarr/Feliz.UseIsVisible
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Feliz.UseIsVisible

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

Installation

Get it from NuGet!

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):

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 = "[email protected]"
                    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 Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK