{"id":17148922,"url":"https://github.com/planttheidea/react-windowed-list","last_synced_at":"2025-04-13T09:32:33.518Z","repository":{"id":57347745,"uuid":"89816794","full_name":"planttheidea/react-windowed-list","owner":"planttheidea","description":null,"archived":false,"fork":false,"pushed_at":"2019-01-05T14:07:54.000Z","size":584,"stargazers_count":60,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-20T08:41:02.594Z","etag":null,"topics":["javascript","react","windowing"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/planttheidea.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-29T22:36:08.000Z","updated_at":"2025-02-11T15:49:20.000Z","dependencies_parsed_at":"2022-08-28T01:40:15.443Z","dependency_job_id":null,"html_url":"https://github.com/planttheidea/react-windowed-list","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/planttheidea%2Freact-windowed-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/planttheidea%2Freact-windowed-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/planttheidea%2Freact-windowed-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/planttheidea%2Freact-windowed-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/planttheidea","download_url":"https://codeload.github.com/planttheidea/react-windowed-list/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248690915,"owners_count":21146231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","react","windowing"],"created_at":"2024-10-14T21:30:27.342Z","updated_at":"2025-04-13T09:32:32.987Z","avatar_url":"https://github.com/planttheidea.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-windowed-list\n\nA fast, versatile virtual-render list component for React.\n\nThis component was originally forked from [`ReactList`](https://github.com/orgsync/react-list), so credit for the core functionality goes to [orgsync](https://github.com/orgsync). I have re-architected it to be more modular, fixed some of the rendering issues, added additional options, and added code coverage.\n\nIf you are migrating from `ReactList`, the following props have changed names:\n\n* `itemsRenderer` =\u003e `containerRenderer`\n* `itemSizeEstimator` =\u003e `getEstimatedItemSize`\n* `itemSizeGetter` =\u003e `getItemSize`\n* `scrollParentGetter` =\u003e `getScrollParent`\n\n## Table of contents\n\n* [Usage](#usage)\n* [Available props](#available-props)\n  * [axis](#axis)\n  * [containerRenderer](#containerrenderer)\n  * [debounceReconciler](#debouncereconciler)\n  * [getEstimatedItemSize](#getestimateditemsize)\n  * [getItemSize](#getitemsize)\n  * [getScrollParent](#getscrollparent)\n  * [initialIndex](#initialindex)\n  * [isHidden](#ishidden)\n  * [isLazy](#islazy)\n  * [itemRenderer](#itemrenderer)\n  * [length](#length)\n  * [minSize](#minsize)\n  * [pageSize](#pageSize)\n  * [threshold](#threshold)\n  * [type](#type)\n  * [usePosition](#useposition)\n  * [useTranslate3d](#usetranslate3d)\n* [Instance methods](#instance-methods)\n  * [getVisibleRange](#getvisiblerange)\n  * [scrollAround](#scrollaround)\n  * [scrollTo](#scrollto)\n* [FAQ](#faq)\n* [Development](#development)\n\n## Usage\n\n```javascript\nimport React, { PureComponent } from \"react\";\nimport WindowedList from \"react-windowed-list\";\n\nconst CONTAINER_STYLE = {\n  height: 500,\n  overflow: \"auto\"\n};\n\nclass MyComponent extends PureComponent {\n  renderItem = (index, key) =\u003e {\n    return (\n      \u003cdiv key={key}\u003eI am rendering stuff for the item at index {index}!\u003c/div\u003e\n    );\n  };\n\n  render() {\n    const { items } = this.props;\n\n    return (\n      \u003cdiv\u003e\n        \u003ch1\u003eList example\u003c/h1\u003e\n\n        \u003cdiv style={CONTAINER_STYLE}\u003e\n          \u003cWindowedList\n            itemRenderer={this.renderItem}\n            length={items.length}\n            type=\"uniform\"\n          /\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\nThe version you install from `npm` includes both the library as you would use in a bundler (such as `webpack`) as well as the compiled file you would use in a `\u003cscript\u003e` tag or with AMD bundlers (such as `RequireJS`). If using the `dist` file, be aware that the following dependencies are considered externals, meaning they are required to exist on the `window` before the library can be included:\n\n* [`react`](https://www.npmjs.com/package/react)\n* [`react-dom`](https://www.npmjs.com/package/react-dom)\n* [`remeasure`](https://www.npmjs.com/package/remeasure)\n\n## Available props\n\n#### axis\n\n_defaults to `y`_\n\nThe axis that this list will scroll on.\n\n#### containerRenderer\n\nA function that receives the rendered list items and a ref. By default, this element is just a `\u003cdiv\u003e`, and generally it only needs to be overridden for use in a `\u003ctable\u003e` or other special case.\n\n**NOTE**: You must set `ref={ref}` on the component that contains the items so that the correct item sizing calculations can be made.\n\n```javascript\nrenderContainer = (items, ref) =\u003e {\n  return (\n    \u003ctable ref={ref}\u003e\n      \u003cthead\u003e\n        \u003cth\u003eItem 1\u003c/th\u003e\n        \u003cth\u003eItem 2\u003c/th\u003e\n        \u003cth\u003eItem 3\u003c/th\u003e\n      \u003c/thead\u003e\n\n      \u003ctbody\u003e{items}\u003c/tbody\u003e\n    \u003c/table\u003e\n  );\n};\n```\n\n#### debounceReconciler\n\nThe number in milliseconds to debounce the reconciliation call to the frame update.\n\nInternally, `updateFrame` is called upon all scroll actions, and upon component update an additional reconciliation call to it is performed to ensure that the frame is at the correct scroll location. While extremely rare, there are edge cases where the eagerness of this reconciliation may cause a render loop. Applying a `debounceReconciler` should ensure that a stable state is reached before attempting reconciliation. This is not usually necessary, and has potential performance ramifications, so only apply as needed.\n\n#### getEstimatedItemSize\n\nA function that should return the estimated size for the element. It receives both the `index` of the element and the internal `cache` of existing elements as parameters.\n\n**NOTE**: This method is only called if no other technique to determine the item size is possible (including through the DOM).\n\n#### getItemSize\n\nA function that should return the size of the element. It receives the `index` of the element as the only parameter.\n\n#### getScrollParent\n\n_defaults to finding the nearest scrollable container_\n\nA function that returns a DOM element or `window` that will be treated as the scrolling container for the list. In most cases, this does not need to be set for the list to work as intended. It is exposed as a prop for more complicated uses where the scrolling container may not initially have an overflow property that enables scrolling, or if you want to specify a container higher up in the DOM tree.\n\n#### initialIndex\n\nThe index to scroll to after mounting.\n\n#### isHidden\n\nIf the element is hidden via CSS and the `type` is not `uniform`, `WindowList` will try to render all the elements because it calculates the size of all of the items as `0`. Setting `isHidden` to `true` when the element is hidden will prevent this behavior.\n\n#### isLazy\n\nEnables lazier loading of list items within the view container. This can improve performance, but can also produce unwanted visual side effects (such as not enough list items rendering), so use at your discretion.\n\n#### itemRenderer\n\nA function that receives `index` and `key` and returns the content to be rendered for the item at that index.\n\n```javascript\nrenderItem = (index, key) =\u003e {\n  const { items } = this.props;\n\n  return \u003cdiv key={key}\u003e{items[index]}\u003c/div\u003e;\n};\n```\n\nIt is also possible to use your own custom `key` property\n\n```javascript\nrenderItem = index =\u003e {\n  const { items } = this.props;\n\n  return \u003cdiv key={items[index].id}\u003e{items[index]}\u003c/div\u003e;\n};\n```\n\n`key` is required, so please ensure the value you pass is not empty and is unique.\n\n#### length\n\n_defaults to `0`_\n\nThe number of items in the list.\n\n#### minSize\n\n_defaults to `1`_\n\nThe minimum number of items to render in the list at any given time.\n\n#### pageSize\n\n_defaults to `10`_\n\nThe number of items to batch up for new renders.\n\n#### threshold\n\n_defaults to `100`_\n\nThe number of pixels to buffer at the beginning and end of the rendered list items.\n\n#### type\n\n_one of: `simple`, `variable`, `uniform`, defaults to `simple`_\n\n* `simple`\n  * Does not cache item sizes or remove items that are above the viewport\n  * This type can be sufficient for many cases when the only requirement is incremental rendering when scrolling\n* `variable`\n  * Caches item sizes as they are rendered so that the items that are above the viewport can be removed as the list is scrolled\n  * This type is preferred when the sizes of the items in the list vary\n  * Supply the `itemSizeGetter` when possible so the entire length of the list can be established beforehand\n* `uniform`\n  * The size of the first item will be used as the size for all other items\n  * This type is preferred when you can guarantee all of your elements will be the same size, which allows the length of the entire list to be calculated beforehand\n  * Multiple items per row are also supported with this type\n\n**NOTE**: If you have set the `type` to be `uniform` and the sizes of the items vary, it causes continuous re-calculation of sizes until the list gives up. If you received a message about WindowedList reaching an unstable state, this is likely the cause.\n\n#### usePosition\n\n_defaults to `false`_\n\nSet to `true` if you choose to not use `transform` CSS property, instead opting for one based on `position`. This is a rare use case, but an example is if you have nested elements that have `position: fixed` and transform is disturbing their window-based position.\n\n**NOTE**: This is a performance decrease, so only apply it if you really need it.\n\n#### useTranslate3d\n\nSet to `true` if you want to use `translate3d` instead of the default `translate` value for the `transform` property. This can be more performant (especially on mobile devices), but is supported by fewer browsers.\n\n## Instance methods\n\n#### getVisibleRange\n\nReturn the indices of the first and last items that are at all visible in the viewport.\n\n```javascript\nclass MyComponent extends PureComponent {\n  list = null;\n\n  renderItem = () =\u003e {\n    ...\n  };\n\n  setListRef = (component) =\u003e {\n    this.list = component;\n  };\n\n  render() {\n    console.log(this.list.getVisibleRange());\n\n    return (\n      \u003cdiv\u003e\n        \u003cWindowedList\n          itemRenderer={this.renderItem}\n          length={this.props.items.length}\n          ref={this.setListRef}\n        /\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n#### scrollAround\n\nPut the element at `index` within the viewport. This is similar to `scrollTo`, but only scroll until the item is visible, not necessarily at the top of the viewport.\n\n**NOTE**: If you are not using `type=\"uniform\"` or an `itemSizeGetter`, you will only be able to scroll to an element that has already been rendered.\n\n```javascript\nclass MyComponent extends PureComponent {\n  list = null;\n\n  renderItem = () =\u003e {\n    ...\n  };\n\n  setListRef = (component) =\u003e {\n    this.list = component;\n  };\n\n  triggerScrollToMiddle = () =\u003e {\n    this.list.scrollAround(Math.floor(this.props.items.length / 2));\n  };\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cWindowedList\n          itemRenderer={this.renderItem}\n          length={this.props.items.length}\n          ref={this.setListRef}\n        /\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n#### scrollTo\n\nPut the element at `index` at the top of the viewport.\n\n**NOTE**: If you are not using `type=\"uniform\"` or an `itemSizeGetter`, you will only be able to scroll to an element that has already been rendered.\n\n```javascript\nclass MyComponent extends PureComponent {\n  list = null;\n\n  renderItem = () =\u003e {\n    ...\n  };\n\n  setListRef = (component) =\u003e {\n    this.list = component;\n  };\n\n  triggerScrollToTop = () =\u003e {\n    this.list.scrollTo(0);\n  };\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cWindowedList\n          itemRenderer={this.renderItem}\n          length={this.props.items.length}\n          ref={this.setListRef}\n        /\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n```\n\n## FAQ\n\n* What is _\"WindowedList failed to reach a stable state.\"_?\n  * This happens when specifying the `uniform` type when the elements are not actually uniform in size. The component attempts to draw only the minimum necessary elements at one time and that minimum element calculation is based off of the first element in the list. When the first element does not match the other elements, the calculation will be wrong and the component will never be able to fully resolve the ideal necessary elements.\n* Why doesn't it work with margins?\n  * The calculations to figure out element positioning and size get significantly more complicated with margins, so they are not supported. Use a transparent `border`, `padding`, or an element with nested elements to achieve the desired spacing.\n* Why is there no `onScroll` event handler?\n  * If you need an `onScroll` handler, just add the handler to the container element wrapping the `WindowedList` component.\n* Why does `WindowList` render all the items when the container is hidden by CSS?\n  * The size of each item is calculated to be `0` as it is hidden, so it tries to fill the container infinitely (or until the list is complete). If you want to prevent this behavior, set `isHidden` to `true` when the container is hidden.\n\n## Development\n\nStandard stuff, clone the repo and `npm i` to get the dependencies. npm scripts available:\n\n* `build` =\u003e builds the distributed JS with `NODE_ENV=development` and with sourcemaps\n* `build:minified` =\u003e builds the distributed JS with `NODE_ENV=production` and minified\n* `dev` =\u003e runs the webpack dev server for the playground\n* `dist` =\u003e runs the `build` and `build:minified`\n* `lint` =\u003e runs ESLint against files in the `src` folder\n* `lint:fix` =\u003e runs ESLint against files in the `src` folder and fixes any fixable issues discovered\n* `prepublish` =\u003e if in publish, runs `prepublish:compile`\n* `prepublish:compile` =\u003e runs the `lint`, `test`, `transpile:lib`, `transpile:es`, and `dist` scripts\n* `test` =\u003e run `ava` with NODE_ENV=test\n* `test:coverage` =\u003e run `ava` with `nyc` to calculate code coverage\n* `test:watch` =\u003e runs `test` but with persistent watcher\n* `transpile:lib` =\u003e run babel against all files in `src` to create files in `lib`\n* `transpile:es` =\u003e run babel against all files in `src` to create files in `es`, preserving ES2015 modules (for\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplanttheidea%2Freact-windowed-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplanttheidea%2Freact-windowed-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplanttheidea%2Freact-windowed-list/lists"}