React Virtuoso

repository·main·Indexed 27 days ago

https://github.com/petyosi/react-virtuoso

A family of virtualization components for React supporting variable-sized items, grouped modes, grids, masonry layouts, and HTML tables. The ecosystem includes @virtuoso.dev/data-table for high-performance virtualized data tables with row/column virtualization, @virtuoso.dev/masonry for virtualized masonry grids, and @virtuoso.dev/gurx, a reactive state management library featuring Cells, Signals, and Realm-based graph structures.

Tokens
251.2K
Snippets
520
Records
933
Agent score
86%

What's inside react-virtuoso

  1. Overview of @virtuoso.dev/data-table features

    main

    The @virtuoso.dev/data-table package provides a high-performance virtualized table with the following capabilities:

    • Virtualization: Both row and column virtualization.
    • Data Management: Support for local and remote data models via localModel() and remoteModel().
    • Column Features: Headers, cells, column groups, sticky pinning, visibility, resizing, reordering, and dynamic schemas.
    • Layout & Organization: Grouped rows and support for sectioned datasets.
    • State & Control: State persistence for table features and model actions, and programmatic control via the table engine.
  2. Overview of @virtuoso.dev/data-table

    main

    @virtuoso.dev/data-table is a virtualized React data table designed for high-performance rendering of large datasets. It supports both row and column virtualization, grouped data, sticky columns, state persistence, and advanced column management including resizing, reordering, and visibility control.

    It is the successor to TableVirtuoso for users requiring a table-specific API rather than a generic virtualized HTML table primitive. The library offers two main integration paths:

    • Shadcn-style wrapper: A pre-styled component set (recommended for speed and polished UI).
    • Headless engine: For custom design systems or non-Tailwind stacks.
  3. Overview of React Virtuoso components

    main

    React Virtuoso is a virtualization library providing components for lists, grids, tables, and chat interfaces. It supports variable-sized items automatically, bi-directional loading (endless scrolling), and high-performance rendering for large datasets.

    Available components include:

    • react-virtuoso: Core virtualization components for lists, grids, and tables (MIT Licensed).
    • Masonry: Virtualized masonry layout for product listings and image galleries (MIT Licensed).
    • Data Table: Virtualized data table with sticky columns, grouped rows, resizing, and reordering (MIT Licensed).
    • Message List: Specialized chat interface component for human/AI conversations (Commercial License).
  4. Understand Reactive Engine Core Concepts

    main

    The state is modeled as a graph of typed nodes. Key concepts include:

    • Cells: Stateful nodes that always hold a current value.
    • Streams: Stateless nodes that emit values to subscribers.
    • Triggers: Valueless streams used to signal events.
    • Resources: Cells with factory initialization and automatic disposal.
    • Operators: Functions like map, filter, scan, debounceTime, throttleTime, and withLatestFrom that transform values.
    • Combinators: Functions like link, pipe, combine, and merge that wire nodes into a graph.
    • Engine: The instance that activates node definitions, propagates published values, and manages subscriptions.
  5. Understand Reactive Engine Core Concepts

    main

    The reactive engine models application logic as a graph of typed nodes. It separates node definitions from runtime state using two primary principles:

    1. Nodes are definitions, not state. A node constructor (like Cell) returns an inert reference (a Symbol). Creating a node records its type, initial value, and behavior in a global registry, but it holds no value itself.
    2. Engines hold state. An Engine instance activates nodes upon first use and owns their values. This allows the same node definition to be used across multiple engines, where each engine maintains its own independent state. This pattern is ideal for reusable components where a library defines the graph once, and each component instance gets its own engine.

    This separation allows for highly reusable logic without re-declaring the node graph for every instance.

    import { Cell, Engine } from '@virtuoso.dev/reactive-engine-core'
    
    const count$ = Cell(0) // a definition, usually at module scope
    
    const a = new Engine()
    const b = new Engine()
    a.pub(count$, 5)
    a.getValue(count$) // 5
    b.getValue(count$) // 0 — independent state
  6. Understand the Reactive Engine mental model

    main

    The Reactive Engine is a state management system based on a graph of typed nodes.

    Key Concept: Nodes are definitions (inert references created at module scope), while Engines hold the state.

    • Node constructors (e.g., Cell, Stream) return symbols that hold no data.
    • An Engine instance activates these nodes lazily and owns their values.
    • This allows for reusable libraries: you define one module-scope graph, and each component instance gets its own Engine with independent state.

    Node Types:

    NodeStateUse Case
    Cell(initial, distinct?)Stateful (has current value)App state, settings
    DerivedCell(initial, source$)Stateful (tracks a source)Read-only computed state
    Stream<T>(distinct?)Stateless (emits values)Events, commands
    Trigger()Stateless (valueless)Signals like 'refetch' or 'reset'
    Resource(factory)Factory-initializedObjects needing setup/disposal
    import { Cell, Stream, Engine, e } from '@virtuoso.dev/reactive-engine-core'
    
    const count$ = Cell(0)
    const engine = new Engine()
    engine.sub(count$, (value) => console.log('count:', value))
    engine.pub(count$, 1) // logs 'count: 1'
  7. Understand the architecture of @virtuoso.dev/data-table features

    main

    Features in @virtuoso.dev/data-table follow a split architecture between Model and UI:

    1. The Model (in the package)

    Feature modules contain the logic and state management. This includes:

    • Streams: Remote-control actions published by the UI.
    • Cells: Reactive state subscribed to by the UI.
    • Reducers: Logic (using e.changeWith, e.link, or e.pipe) that wires streams and cells together, including mutations to core cells like columns$.
    • Helpers: Pure functions operating on feature types.

    2. The UI (in the registry)

    UI components are not shipped in the npm package. Instead, they are provided via a registry (similar to shadcn). This allows consumers to npx shadcn add the components, giving them full ownership of the source code for free restyling without needing to fork the core package.

  8. How distinctness and computation cycles work

    main

    Every engine.pub(node$, value) call triggers a complete, synchronous computation cycle:

    1. Execution Map: The engine performs a topological sort of all nodes reachable from the published node.
    2. Walk: The engine walks the map (sources before sinks), computing new values.
    3. Distinct Check: The node's comparator checks the new value against the current value. If they are equal, the node does not emit, and downstream nodes are pruned.
    4. Subscriptions: All nodes that emitted fire their subscriptions within the engine context.

    Note on Comparators: The comparator runs during computation, not as a pre-publish check. For the first computation of a node, the comparator sees prev === undefined.

  9. Choose a Data Model for @virtuoso.dev/data-table

    main

    When using the Data Table component, you must choose a model to manage your rows. The model owns the row data, while columns handle the rendering.

    There are two primary model types:

    • localModel(): Use this when rows are already loaded in the browser. It supports deriving displayed rows through filtering, sorting, grouping, and editing actions.
    • remoteModel(): Use this when rows are fetched from an API via request parameters, cursors, or changes in the rendered range.

    Both models can persist action state (such as filter values, sort choices, or grouping modes) using opt-in adapters, though the row data itself is not persisted.

  10. Understand the Virtuoso Message List License

    main

    The @virtuoso.dev/message-list component is a commercial product governed by an End User License Agreement (EULA) with Martiti 2 Ltd.

    Key Licensing Terms:

    • License Grant: Provides a worldwide, non-exclusive, non-transferable, and sublicensable license to use the software.
    • Deployment Restrictions: You may not use the software for projects that directly or indirectly compete with Martiti 2 Ltd, nor for projects intended to be development toolkits, application builders, or website builders (unless expressly agreed in writing).
    • Source Code Protection: Modification, decompilation, disassembly, or reverse engineering of the source code is strictly prohibited.
    • License Keys: The software may require a license key to ensure compliance. The software may issue warnings if it detects usage inconsistent with the agreement (e.g., using versions released after license expiration).
  11. Features of Reactive Engine Router

    main

    The @virtuoso.dev/reactive-engine-router package provides the following capabilities:

    • Routes: Typed route definitions that support parameters.
    • Layouts: Nested layout components matched by path, utilizing slot/fill composition via LayoutSlot and LayoutSlotFill.
    • Guards: Support for both synchronous and asynchronous navigation guards that can allow navigation to continue, redirect the user, or navigate to a different route.
  12. Understand Reactive Engine execution cycles

    main

    Every engine.pub(node$, value) call triggers a synchronous, complete computation cycle consisting of:

    1. Execution Map Generation: A topological sort of all nodes reachable from the published node.
    2. Topological Walk: The engine walks the map from sources to sinks, computing new values.
    3. Distinct Check: Each node's comparator determines if it should emit. If a node does not emit, downstream nodes are pruned from the cycle.
    4. Subscription Execution: All nodes that emitted fire their subscriptions within the engine context.

    By the time pub returns, the entire graph is consistent.