Legend List

repository·main·Indexed 25 days ago

https://github.com/legendapp/legend-list

A high-performance, 100% JavaScript list component for React Native and Web designed as a drop-in replacement for FlatList and FlashList. It supports dynamically sized items, bidirectional infinite scrolling, and item recycling without native dependencies. Features include maintainVisibleContentPosition for scroll stabilization, an alwaysRender prop to bypass virtualization for specific items, and platform-specific entry points for strict typing.

Tokens
5.2K
Snippets
7
Records
34
Agent score
86%

What's inside @legendapp/list

  1. Understand the Example and Fixture Modes

    main

    The project distinguishes between two distinct catalog modes to separate user-facing demonstrations from internal debugging tools:

    1. examples (Default Mode): A curated, polished catalog of product-style surfaces (e.g., Messaging, Commerce) designed for users. This is the default mode for all standard scripts.
    2. fixtures (Internal Mode): A catalog containing existing screens, debug behaviors, comparison/benchmark demos, and internal validation tools. This mode is accessed via explicit scripts.

    Key Constraints:

    • Modes are selected via environment variables or package scripts, not via URL path segments.
    • The two modes are self-contained; do not add in-app links between examples and fixtures.
    • example-web must not import files from the example/ (native) directory; all shared logic must reside in a neutral shared location.
  2. Note on Old Architecture configuration

    main

    The example-oldarch/ directory contains an application configured specifically for the old architecture.

    Key configuration details:

    • The Expo config explicitly sets newArchEnabled: false.
    • It uses a unique app ID (com.legendapp.listtest.o) to allow coexistence with the main example/ app on the same device.
  3. Run tests for Legend List

    main

    Legend List uses the Bun test runner with TypeScript support. You can execute the test suite using the following commands from the project root:

    • bun test: Run all tests.
    • bun test:watch: Run tests in watch mode.
    • bun test:coverage: Run tests and generate coverage reports.
    bun test
    bun test:watch
    bun test:coverage
  4. Get started with the LegendList test application

    main

    To run the LegendList test application (an Expo project used as a development playground), follow these steps:

    1. Install dependencies using npm.
    2. Start the application using the Expo CLI.
    3. Choose an environment to run the app (Development build, Android emulator, iOS simulator, or Expo Go) from the terminal output.

    Development is performed by editing files within the app directory, as the project utilizes file-based routing.

    npm install
    npx expo start
  5. Run the LegendList test application

    main

    The example/ directory contains an Expo project used as a development playground for testing LegendList features. This project uses file-based routing and is configured for the New Architecture only.

    To run the application, follow these steps:

    1. Install dependencies using npm install.
    2. Start the Expo development server using npx expo start.
    3. Choose an option from the terminal output to open the app in a development build, Android emulator, iOS simulator, or Expo Go.
    npm install
    npx expo start
  6. Use platform-specific entrypoints for strict typing

    main

    To ensure strict type safety for platform-specific props (like style, onScroll, or refScrollView), you should import from the platform-specific subpaths instead of the base package. This provides strong React Native types or strong DOM/CSS types depending on your environment.

    • For React Native projects, use @legendapp/list/react-native.
    • For Web projects, use @legendapp/list/web.

    Using these subpaths ensures that pass-through props (such as ScrollViewProps in RN or HTMLAttributes in Web) are correctly typed for your target platform.

  7. Install @legendapp/list

    main

    Install Legend List using your preferred package manager. It is a high-performance, 100% JavaScript list component for React Native that serves as a drop-in replacement for FlatList and FlashList.

    # Using Bun
    bun add @legendapp/list
    
    # Using npm
    npm install @legendapp/list
    
    # Using Yarn
    yarn add @legendapp/list
  8. Fix SectionList sticky headers detaching on data changes

    main

    In SectionList, sticky headers may visually detach from their section if items are conditionally added or removed from a section, causing the header to move to a new flattened index while retaining its old index.

    This issue was resolved by moving away from using a static index prop (which was captured during the initial render of a Container) to a dynamic containerItemIndex{id} signal. This ensures that sticky positioning, recycling context, and web DOM reordering always use the most current flattened index, even when the item's key and data remain unchanged but its position in the list shifts.

  9. Use LegendList component

    main

    Implement LegendList by providing data and renderItem. For optimal performance, it is recommended to use keyExtractor and enable recycleItems. Use maintainVisibleContentPosition to prevent scroll jumping during layout changes.

    import React, { useRef } from "react"
    import { View, Image, Text, StyleSheet } from "react-native"
    import { LegendList, LegendListRef, LegendListRenderItemProps } from "@legendapp/list/react-native"
    
    // Define the type for your data items
    interface UserData {
        id: string;
        name: string;
        photoUri: string;
    }
    
    const LegendListExample = () => {
        // Optional: Ref for accessing list methods (e.g., scrollTo)
        const listRef = useRef<LegendListRef | null>(null)
    
        const data = []
    
        const renderItem = ({ item }: LegendListRenderItemProps<UserData>) => {
            return (
                <View>
                    <Image source={{ uri: item.photoUri }} />
                    <Text>{item.name}</Text>
                </View>
            )
        }
    
        return (
            <LegendList
                // Required Props
                data={data}
                renderItem={renderItem}
    
                // Recommended props (Improves performance)
                keyExtractor={(item) => item.id}
                recycleItems={true}
    
                // Recommended if data can change
                maintainVisibleContentPosition
    
                ref={listRef}
            />
        )
    }
    
    export default LegendListExample