diff --git a/website/sandboxes/memoized-list-items/index.js b/website/sandboxes/memoized-list-items/index.js
new file mode 100644
index 0000000..3ba6912
--- /dev/null
+++ b/website/sandboxes/memoized-list-items/index.js
@@ -0,0 +1,83 @@
+import React, { PureComponent } from 'react';
+import ReactDOM from 'react-dom';
+import memoize from 'memoize-one';
+import { FixedSizeList as List } from 'react-window';
+
+const generateItems = numItems =>
+ Array(numItems)
+ .fill(true)
+ .map(_ => ({
+ isActive: false,
+ label: Math.random()
+ .toString(36)
+ .substr(2),
+ }));
+
+// If list items are expensive to render,
+// Consider using PureComponent to avoid unnecessary re-renders.
+// https://reactjs.org/docs/react-api.html#reactpurecomponent
+class ListItem extends PureComponent {
+ render() {
+ const { data, index, style } = this.props;
+
+ // Data passed to List as "itemData" is available as props.data
+ const { items, toggleItemActive } = data;
+ const item = items[index];
+
+ return (
+
toggleItemActive(index)} style={style}>
+ {item.label} is {item.isActive ? 'active' : 'inactive'}
+
+ );
+ }
+}
+
+// This helper function memoizes incoming props,
+// To avoid causing unnecessary re-renders pure ListItem components.
+// This is only needed since we are passing multiple props with a wrapper object.
+// If we were only passing a single, stable value (e.g. items),
+// We could just pass the value directly.
+const getItemData = memoize((items, toggleItemActive) => ({
+ items,
+ toggleItemActive,
+}));
+
+class App extends PureComponent {
+ state = {
+ items: generateItems(1000),
+ };
+
+ toggleItemActive = index =>
+ this.setState(prevState => {
+ const item = prevState.items[index];
+ const items = prevState.items.concat();
+ items[index] = {
+ ...item,
+ isActive: !item.isActive,
+ };
+ return { items };
+ });
+
+ render() {
+ const { items } = this.state;
+
+ // Bundle additional data to list items using the "itemData" prop.
+ // It will be accessible to item renderers as props.data.
+ // Memoize this data to avoid bypassing shouldComponentUpdate().
+ const itemData = getItemData(items, this.toggleItemActive);
+
+ return (
+
+ {ListItem}
+
+ );
+ }
+}
+
+ReactDOM.render(, document.getElementById('root'));
diff --git a/website/sandboxes/memoized-list-items/package.json b/website/sandboxes/memoized-list-items/package.json
new file mode 100644
index 0000000..82e41d1
--- /dev/null
+++ b/website/sandboxes/memoized-list-items/package.json
@@ -0,0 +1,10 @@
+{
+ "description": "Demo of react-window with advanced memoization techniques",
+ "main": "src/index.js",
+ "dependencies": {
+ "memoize-one": "^4",
+ "react": "^16",
+ "react-dom": "^16",
+ "react-window": "^1"
+ }
+}
diff --git a/website/sandboxes/memoized-list-items/styles.css b/website/sandboxes/memoized-list-items/styles.css
new file mode 100644
index 0000000..5d3455d
--- /dev/null
+++ b/website/sandboxes/memoized-list-items/styles.css
@@ -0,0 +1,19 @@
+html {
+ font-family: sans-serif;
+ font-size: 12px;
+}
+
+.List {
+ border: 1px solid #d9dddd;
+}
+
+.ListItemEven,
+.ListItemOdd {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.ListItemEven {
+ background-color: #f8f8f0;
+}
diff --git a/website/src/code/MemoizedListItems.js b/website/src/code/MemoizedListItems.js
index 4564696..7a0dcaa 100644
--- a/website/src/code/MemoizedListItems.js
+++ b/website/src/code/MemoizedListItems.js
@@ -44,27 +44,26 @@ class Example extends PureComponent {
toggleItemActive = index =>
this.setState(prevState => {
const item = prevState.items[index];
- return {
- items: {
- ...prevState.items,
- [index]: {
- ...item,
- isActive: !item.isActive,
- },
- },
+ const items = prevState.items.concat();
+ items[index] = {
+ ...item,
+ isActive: !item.isActive,
};
+ return {items};
});
render() {
+ const { items } = this.state;
+
// Bundle additional data to list items using the "itemData" prop.
// It will be accessible to item renderers as props.data.
// Memoize this data to avoid bypassing shouldComponentUpdate().
- const itemData = getItemData(this.state.items, this.toggleItemActive);
+ const itemData = getItemData(items, this.toggleItemActive);
return (
- Array(1000)
+const generateItems = numItems =>
+ Array(numItems)
.fill(true)
.map(_ => ({
isActive: false,
@@ -49,22 +49,18 @@ class ItemRenderer extends PureComponent {
export default class MemoizedListItemsExample extends PureComponent {
state = {
- items: generateItems(),
+ items: generateItems(1000),
};
toggleItemActive = index =>
this.setState(prevState => {
const item = prevState.items[index];
-
- return {
- items: {
- ...prevState.items,
- [index]: {
- ...item,
- isActive: !item.isActive,
- },
- },
+ const items = prevState.items.concat();
+ items[index] = {
+ ...item,
+ isActive: !item.isActive,
};
+ return { items };
});
render() {
@@ -82,7 +78,7 @@ export default class MemoizedListItemsExample extends PureComponent {