{"id":11909,"library":"react-window-infinite-loader","title":"React Window Infinite Loader","description":"react-window-infinite-loader provides utilities for implementing infinite scrolling lists with `react-window`. It is inspired by `react-virtualized`'s `InfiniteLoader` but is specifically designed to work as a lightweight companion for `react-window`'s fixed and variable size lists. The current stable version is 2.0.1, released as of this documentation. The library's release cadence is tied to its maintainer's work on `react-window` and `react-virtualized`, often seeing updates for React compatibility or minor feature enhancements. Key differentiators include its tight integration with `react-window`, offering both a `useInfiniteLoader` hook for functional components and a `InfiniteLoader` component for class-based or render-prop patterns, making it adaptable to various component architectures. It helps manage the loaded state of rows and triggers data loading as users scroll near the end of the list.","status":"active","version":"2.0.1","language":"javascript","source_language":"en","source_url":"https://github.com/bvaughn/react-window-infinite-loader","tags":["javascript","typescript"],"install":[{"cmd":"npm install react-window-infinite-loader","lang":"bash","label":"npm"},{"cmd":"yarn add react-window-infinite-loader","lang":"bash","label":"yarn"},{"cmd":"pnpm add react-window-infinite-loader","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for React component and hook functionality.","package":"react","optional":false},{"reason":"Required for rendering React components.","package":"react-dom","optional":false},{"reason":"Core virtualization library this package extends, not a direct dependency but a necessary peer for usage.","package":"react-window","optional":false}],"imports":[{"note":"This is the recommended hook for functional components. It's a named export, not a default.","wrong":"import useInfiniteLoader from 'react-window-infinite-loader'","symbol":"useInfiniteLoader","correct":"import { useInfiniteLoader } from 'react-window-infinite-loader'"},{"note":"The `InfiniteLoader` component is a named export. ESM `import` is the primary usage pattern.","wrong":"const InfiniteLoader = require('react-window-infinite-loader')","symbol":"InfiniteLoader","correct":"import { InfiniteLoader } from 'react-window-infinite-loader'"},{"note":"Import types explicitly when using TypeScript for better type checking.","symbol":"InfiniteLoaderProps","correct":"import type { InfiniteLoaderProps } from 'react-window-infinite-loader'"}],"quickstart":{"code":"import { useInfiniteLoader } from 'react-window-infinite-loader';\nimport { FixedSizeList } from 'react-window';\nimport React, { useState, useCallback } from 'react';\n\nconst Row = ({ index, style, isLoaded }) => (\n  <div style={style}>\n    {isLoaded ? `Row ${index}` : `Loading row ${index}...`}\n  </div>\n);\n\nconst ExampleList = ({ itemCount, isRowLoaded, loadMoreRows }) => {\n  const [items, setItems] = useState(Array(itemCount).fill(false));\n\n  const infiniteLoaderProps = {\n    isRowLoaded,\n    loadMoreRows,\n    itemCount,\n    threshold: 5,\n    minimumBatchSize: 10\n  };\n\n  const onRowsRendered = useInfiniteLoader(infiniteLoaderProps);\n\n  return (\n    <FixedSizeList\n      height={300}\n      itemCount={itemCount}\n      itemSize={50}\n      width={500}\n      onRowsRendered={onRowsRendered}\n    >\n      {({ index, style }) => (\n        <Row index={index} style={style} isLoaded={isRowLoaded({ index })} />\n      )}\n    </FixedSizeList>\n  );\n};\n\nfunction App() {\n  const ROW_COUNT = 1000;\n  const isItemLoaded = ({ index }) => index < loadedItems.length;\n  const [loadedItems, setLoadedItems] = useState(Array(50).fill(true));\n\n  const loadMore = useCallback(async (startIndex, stopIndex) => {\n    console.log(`Loading rows from ${startIndex} to ${stopIndex}`);\n    // Simulate API call\n    await new Promise(resolve => setTimeout(resolve, 1000));\n\n    setLoadedItems(prev => {\n      const newItems = [...prev];\n      for (let i = startIndex; i <= stopIndex; i++) {\n        if (!newItems[i]) {\n          newItems[i] = true;\n        }\n      }\n      return newItems;\n    });\n  }, []);\n\n  return (\n    <ExampleList\n      itemCount={ROW_COUNT}\n      isRowLoaded={isItemLoaded}\n      loadMoreRows={loadMore}\n    />\n  );\n}\n\nexport default App;\n","lang":"typescript","description":"This example demonstrates how to use the `useInfiniteLoader` hook with `react-window`'s `FixedSizeList` to implement a basic infinite scrolling list. It simulates fetching data asynchronously and updates the list as new rows are loaded."},"warnings":[{"fix":"Update the render prop signature for `InfiniteLoader` from `{ onItemsRendered, listRef }` to `{ onRowsRendered }`. Pass the `onRowsRendered` prop to your `react-window` list component.","message":"The `InfiniteLoader` component underwent significant changes in version 2. The `onItemsRendered` parameter in its child function was renamed to `onRowsRendered`, and the `listRef` parameter was entirely removed. Existing code using the `InfiniteLoader` component from v1 will break if not updated to reflect these parameter changes.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure your `loadMoreRows` function is `async` or explicitly returns a Promise. For example: `async (startIndex, stopIndex) => { await fetchData(startIndex, stopIndex); }` or `(startIndex, stopIndex) => { return new Promise(resolve => fetchData(startIndex, stopIndex).then(resolve)); }`.","message":"It's crucial that the `loadMoreRows` prop passed to `useInfiniteLoader` or `InfiniteLoader` returns a Promise. If it does not return a Promise that resolves when data is loaded, the component will not correctly track the loading state, potentially leading to repeated fetches or a broken infinite scroll experience.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure your `isRowLoaded` function correctly checks the loaded state for the given `index` against your data source. This often involves checking if `index < yourDataSource.length` or if a specific item in your data array at `index` is defined.","message":"Incorrectly managing the `isRowLoaded` state can lead to either rows perpetually showing as loading or `loadMoreRows` being called too frequently or not at all. The `isRowLoaded` function must accurately reflect whether the data for a given `index` is available.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Make sure your `loadMoreRows` function returns a Promise that resolves when data fetching is complete. If using `async/await`, ensure the `async` keyword is present. If using a standard Promise, ensure it is explicitly returned.","cause":"`loadMoreRows` did not return a Promise.","error":"TypeError: Cannot read properties of undefined (reading 'then')"},{"fix":"Ensure `useInfiniteLoader` is only called at the top level of a functional React component or within another custom hook that itself adheres to React Hook rules.","cause":"`useInfiniteLoader` is called outside of a functional React component or another custom hook.","error":"React Hook 'useInfiniteLoader' is called in a function that is neither a React function component nor a custom React Hook function."}],"ecosystem":"npm"}