Skip to content

Commit 3c9a558

Browse files
author
Brian Vaughn
committed
Pass itemData to itemKey
1 parent 94de9a7 commit 3c9a558

File tree

9 files changed

+124
-24
lines changed

9 files changed

+124
-24
lines changed

src/__tests__/FixedSizeGrid.js

+18
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,24 @@ describe('FixedSizeGrid', () => {
561561
expect(keyMapItemRenderer.mock.calls[1][0].columnIndex).toBe(2);
562562
expect(keyMapItemRenderer.mock.calls[1][0].rowIndex).toBe(1);
563563
});
564+
565+
it('should receive a data value if itemData is provided', () => {
566+
const itemKey = jest.fn(
567+
({ columnIndex, data, rowIndex }) => `${columnIndex}-${rowIndex}`
568+
);
569+
const itemData = {};
570+
ReactTestRenderer.create(
571+
<FixedSizeGrid
572+
{...defaultProps}
573+
itemData={itemData}
574+
itemKey={itemKey}
575+
/>
576+
);
577+
expect(itemKey).toHaveBeenCalled();
578+
expect(
579+
itemKey.mock.calls.filter(([params]) => params.data === itemData)
580+
).toHaveLength(itemKey.mock.calls.length);
581+
});
564582
});
565583

566584
describe('refs', () => {

src/__tests__/FixedSizeList.js

+16
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,22 @@ describe('FixedSizeList', () => {
471471
expect(keyMapItemRenderer.mock.calls[0][0].index).toBe(0);
472472
expect(keyMapItemRenderer.mock.calls[1][0].index).toBe(2);
473473
});
474+
475+
it('should receive a data value if itemData is provided', () => {
476+
const itemKey = jest.fn(index => index);
477+
const itemData = {};
478+
ReactTestRenderer.create(
479+
<FixedSizeList
480+
{...defaultProps}
481+
itemData={itemData}
482+
itemKey={itemKey}
483+
/>
484+
);
485+
expect(itemKey).toHaveBeenCalled();
486+
expect(
487+
itemKey.mock.calls.filter(([index, data]) => data === itemData)
488+
).toHaveLength(itemKey.mock.calls.length);
489+
});
474490
});
475491

476492
describe('refs', () => {

src/createGridComponent.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ import { createElement, PureComponent } from 'react';
66
export type ScrollToAlign = 'auto' | 'center' | 'start' | 'end';
77

88
type itemSize = number | ((index: number) => number);
9-
type ItemKeyGetter = (indices: {
10-
columnIndex: number,
11-
rowIndex: number,
12-
}) => any;
139

1410
type RenderComponentProps<T> = {|
1511
columnIndex: number,
@@ -56,7 +52,11 @@ export type Props<T> = {|
5652
innerRef?: any,
5753
innerTagName?: string,
5854
itemData: T,
59-
itemKey?: ItemKeyGetter,
55+
itemKey?: (params: {|
56+
columnIndex: number,
57+
data: T,
58+
rowIndex: number,
59+
|}) => any,
6060
onItemsRendered?: OnItemsRenderedCallback,
6161
onScroll?: OnScrollCallback,
6262
outerRef?: any,
@@ -112,7 +112,7 @@ type ValidateProps = (props: Props<any>) => void;
112112

113113
const IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
114114

115-
const defaultItemKey: ItemKeyGetter = ({ columnIndex, rowIndex }) =>
115+
const defaultItemKey = ({ columnIndex, data, rowIndex }) =>
116116
`${rowIndex}:${columnIndex}`;
117117

118118
export default function createGridComponent({
@@ -317,7 +317,7 @@ export default function createGridComponent({
317317
columnIndex,
318318
data: itemData,
319319
isScrolling: useIsScrolling ? isScrolling : undefined,
320-
key: itemKey({ columnIndex, rowIndex }),
320+
key: itemKey({ columnIndex, data: itemData, rowIndex }),
321321
rowIndex,
322322
style: this._getItemStyle(rowIndex, columnIndex),
323323
})

src/createListComponent.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ export type ScrollToAlign = 'auto' | 'center' | 'start' | 'end';
77

88
type itemSize = number | ((index: number) => number);
99
type Direction = 'horizontal' | 'vertical';
10-
type ItemKeyGetter = (index: number) => any;
1110

1211
type RenderComponentProps<T> = {|
1312
data: T,
@@ -44,7 +43,7 @@ export type Props<T> = {|
4443
innerTagName?: string,
4544
itemCount: number,
4645
itemData: T,
47-
itemKey?: ItemKeyGetter,
46+
itemKey?: (index: number, data: T) => any,
4847
itemSize: itemSize,
4948
onItemsRendered?: onItemsRenderedCallback,
5049
onScroll?: onScrollCallback,
@@ -97,7 +96,7 @@ type ValidateProps = (props: Props<any>) => void;
9796

9897
const IS_SCROLLING_DEBOUNCE_INTERVAL = 150;
9998

100-
const defaultItemKey: ItemKeyGetter = index => index;
99+
const defaultItemKey = (index: number, data: any) => index;
101100

102101
export default function createListComponent({
103102
getItemOffset,
@@ -253,7 +252,7 @@ export default function createListComponent({
253252
items.push(
254253
createElement(children, {
255254
data: itemData,
256-
key: itemKey(index),
255+
key: itemKey(index, itemData),
257256
index,
258257
isScrolling: useIsScrolling ? isScrolling : undefined,
259258
style: this._getItemStyle(index),

src/test.js.flow

+70-4
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,13 @@ const assertCustomType = (value: ItemData) => {};
2828
assertString(data);
2929
return null;
3030
};
31-
<FixedSizeList width={0} height={0} itemSize={0} itemCount={0} itemData={1}>
31+
const itemKey = (index, data) => {
32+
assertNumber(data);
33+
// $FlowFixMe expected
34+
assertString(data);
35+
return index;
36+
};
37+
<FixedSizeList width={0} height={0} itemSize={0} itemCount={0} itemData={1} itemKey={itemKey}>
3238
{Item}
3339
</FixedSizeList>;
3440
}
@@ -40,6 +46,12 @@ const assertCustomType = (value: ItemData) => {};
4046
assertString(data);
4147
return null;
4248
};
49+
const itemKey = (index, data) => {
50+
assertCustomType(data);
51+
// $FlowFixMe expected
52+
assertString(data);
53+
return index;
54+
};
4355
<FixedSizeList
4456
width={0}
4557
height={0}
@@ -49,6 +61,7 @@ const assertCustomType = (value: ItemData) => {};
4961
num: 123,
5062
str: 'abc',
5163
}}
64+
itemKey={itemKey}
5265
>
5366
{Item}
5467
</FixedSizeList>;
@@ -61,7 +74,13 @@ const assertCustomType = (value: ItemData) => {};
6174
assertEmpty(data);
6275
return null;
6376
};
64-
<FixedSizeList width={0} height={0} itemSize={0} itemCount={0}>
77+
const itemKey = (index, data) => {
78+
assertVoid(data);
79+
// $FlowFixMe expected
80+
assertString(data);
81+
return index;
82+
};
83+
<FixedSizeList width={0} height={0} itemSize={0} itemCount={0} itemKey={itemKey}>
6584
{Item}
6685
</FixedSizeList>;
6786
}
@@ -75,12 +94,19 @@ const assertCustomType = (value: ItemData) => {};
7594
assertString(data);
7695
return null;
7796
};
97+
const itemKey = (index, data) => {
98+
assertNumber(data);
99+
// $FlowFixMe expected
100+
assertString(data);
101+
return index;
102+
};
78103
<VariableSizeList
79104
width={0}
80105
height={0}
81106
itemSize={0}
82107
itemCount={0}
83108
itemData={1}
109+
itemKey={itemKey}
84110
>
85111
{Item}
86112
</VariableSizeList>;
@@ -93,6 +119,12 @@ const assertCustomType = (value: ItemData) => {};
93119
assertString(data);
94120
return null;
95121
};
122+
const itemKey = (index, data) => {
123+
assertCustomType(data);
124+
// $FlowFixMe expected
125+
assertString(data);
126+
return index;
127+
};
96128
<VariableSizeList
97129
width={0}
98130
height={0}
@@ -102,6 +134,7 @@ const assertCustomType = (value: ItemData) => {};
102134
num: 123,
103135
str: 'abc',
104136
}}
137+
itemKey={itemKey}
105138
>
106139
{Item}
107140
</VariableSizeList>;
@@ -114,7 +147,13 @@ const assertCustomType = (value: ItemData) => {};
114147
assertEmpty(data);
115148
return null;
116149
};
117-
<VariableSizeList width={0} height={0} itemSize={0} itemCount={0}>
150+
const itemKey = (index, data) => {
151+
assertVoid(data);
152+
// $FlowFixMe expected
153+
assertString(data);
154+
return index;
155+
};
156+
<VariableSizeList width={0} height={0} itemSize={0} itemCount={0} itemKey={itemKey}>
118157
{Item}
119158
</VariableSizeList>;
120159
}
@@ -129,7 +168,13 @@ const assertCustomType = (value: ItemData) => {};
129168
return null;
130169
}
131170
}
132-
<VariableSizeList width={0} height={0} itemSize={0} itemCount={0}>
171+
const itemKey = (index, data) => {
172+
assertVoid(data);
173+
// $FlowFixMe expected
174+
assertString(data);
175+
return index;
176+
};
177+
<VariableSizeList width={0} height={0} itemSize={0} itemCount={0} itemKey={itemKey}>
133178
{Item}
134179
</VariableSizeList>;
135180
}
@@ -143,6 +188,12 @@ const assertCustomType = (value: ItemData) => {};
143188
assertString(data);
144189
return null;
145190
};
191+
const itemKey = ({ columnIndex, data, rowIndex }) => {
192+
assertNumber(data);
193+
// $FlowFixMe expected
194+
assertString(data);
195+
return `${columnIndex}:${rowIndex}`;
196+
};
146197
<FixedSizeGrid
147198
width={0}
148199
height={0}
@@ -151,6 +202,7 @@ const assertCustomType = (value: ItemData) => {};
151202
columnWidth={0}
152203
columnCount={0}
153204
itemData={1}
205+
itemKey={itemKey}
154206
>
155207
{Item}
156208
</FixedSizeGrid>;
@@ -163,6 +215,12 @@ const assertCustomType = (value: ItemData) => {};
163215
assertString(data);
164216
return null;
165217
};
218+
const itemKey = ({ columnIndex, data, rowIndex }) => {
219+
assertCustomType(data);
220+
// $FlowFixMe expected
221+
assertString(data);
222+
return `${columnIndex}:${rowIndex}`;
223+
};
166224
<FixedSizeGrid
167225
width={0}
168226
height={0}
@@ -174,6 +232,7 @@ const assertCustomType = (value: ItemData) => {};
174232
num: 123,
175233
str: 'abc',
176234
}}
235+
itemKey={itemKey}
177236
>
178237
{Item}
179238
</FixedSizeGrid>;
@@ -186,13 +245,20 @@ const assertCustomType = (value: ItemData) => {};
186245
assertEmpty(data);
187246
return null;
188247
};
248+
const itemKey = ({ columnIndex, data, rowIndex }) => {
249+
assertVoid(data);
250+
// $FlowFixMe expected
251+
assertString(data);
252+
return `${columnIndex}:${rowIndex}`;
253+
};
189254
<FixedSizeGrid
190255
width={0}
191256
height={0}
192257
rowHeight={0}
193258
rowCount={0}
194259
columnWidth={0}
195260
columnCount={0}
261+
itemKey={itemKey}
196262
>
197263
{Item}
198264
</FixedSizeGrid>;

website/sandboxes/memoized-list-items/index.js

-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ const createItemData = memoize((items, toggleItemActive) => ({
4545
// In this example, "items" is an Array of objects to render,
4646
// and "toggleItemActive" is a function that updates an item's state.
4747
function Example({ height, items, toggleItemActive, width }) {
48-
4948
// Bundle additional data to list items using the "itemData" prop.
5049
// It will be accessible to item renderers as props.data.
5150
// Memoize this data to avoid bypassing shouldComponentUpdate().

website/src/code/FixedSizeGridItemKey.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
function itemKey({ columnIndex, rowIndex }) {
2-
// Find the item for the specified indices:
3-
const item = items[rowIndex];
1+
function itemKey({ columnIndex, data, rowIndex }) {
2+
// Find the item for the specified indices.
3+
// In this case "data" is an Array that was passed to Grid as "itemData".
4+
const item = data[rowIndex];
45

56
// Return a value that uniquely identifies this item.
67
// For a grid, this key must represent both the row and column.

website/src/code/FixedSizeListItemKey.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
function itemKey(index) {
2-
// Find the item at the specified index:
3-
const item = items[index];
1+
function itemKey(index, data) {
2+
// Find the item at the specified index.
3+
// In this case "data" is an Array that was passed to List as "itemData".
4+
const item = data[index];
45

56
// Return a value that uniquely identifies this item.
67
// Typically this will be a UID of some sort.

website/src/routes/api/FixedSizeList.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ const PROPS = [
293293
</p>
294294
<p>
295295
Note that using this parameter will result in an additional render
296-
call after scrolling has stopped (when <code>isScrolling</code> changes
297-
from true to false).
296+
call after scrolling has stopped (when <code>isScrolling</code>{' '}
297+
changes from true to false).
298298
</p>
299299
<p>
300300
<Link to="/examples/list/scrolling-indicators">

0 commit comments

Comments
 (0)