Added memoized-list-items sandbox
This commit is contained in:
@@ -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 (
|
||||
<div onClick={() => toggleItemActive(index)} style={style}>
|
||||
{item.label} is {item.isActive ? 'active' : 'inactive'}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (
|
||||
<List
|
||||
height={150}
|
||||
itemCount={items.length}
|
||||
itemData={itemData}
|
||||
itemSize={35}
|
||||
width={300}
|
||||
>
|
||||
{ListItem}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 (
|
||||
<List
|
||||
height={height}
|
||||
itemCount={listData.length}
|
||||
itemCount={items.length}
|
||||
itemData={itemData}
|
||||
itemSize={35}
|
||||
width={width}
|
||||
|
||||
@@ -8,8 +8,8 @@ import CODE from '../../code/MemoizedListItems.js';
|
||||
|
||||
import styles from './shared.module.css';
|
||||
|
||||
const generateItems = () =>
|
||||
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 {
|
||||
<FixedSizeList
|
||||
className={styles.List}
|
||||
height={150}
|
||||
itemCount={1000}
|
||||
itemCount={items.length}
|
||||
itemData={itemData}
|
||||
itemSize={35}
|
||||
width={300}
|
||||
|
||||
Reference in New Issue
Block a user