Skip to content

Commit 28c069d

Browse files
committed
fix: Do not crash when list removed
1 parent 0e5346d commit 28c069d

File tree

6 files changed

+64
-24
lines changed

6 files changed

+64
-24
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ module.exports = {
99
'react/no-find-dom-node': 0,
1010
'no-dupe-class-members': 0,
1111
'react/sort-comp': 0,
12+
'no-confusing-arrow': 0,
1213
},
1314
};

examples/basic.tsx

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const TYPES = [
4545
];
4646

4747
const Demo = () => {
48+
const [destroy, setDestroy] = React.useState(false);
4849
const [type, setType] = React.useState('dom');
4950
const listRef = React.useRef<List>(null);
5051

@@ -66,26 +67,6 @@ const Demo = () => {
6667
</label>
6768
))}
6869

69-
<List
70-
ref={listRef}
71-
data={data}
72-
height={200}
73-
itemHeight={30}
74-
itemKey="id"
75-
style={{
76-
border: '1px solid red',
77-
boxSizing: 'border-box',
78-
}}
79-
>
80-
{(item, _, props) =>
81-
(type === 'dom' ? (
82-
<ForwardMyItem {...item} {...props} />
83-
) : (
84-
<TestItem {...item} {...props} />
85-
))
86-
}
87-
</List>
88-
8970
<button
9071
type="button"
9172
onClick={() => {
@@ -138,6 +119,41 @@ const Demo = () => {
138119
>
139120
Scroll To key 50 (auto)
140121
</button>
122+
123+
<button
124+
type="button"
125+
onClick={() => {
126+
listRef.current.scrollTo({
127+
index: 50,
128+
align: 'top',
129+
});
130+
setDestroy(true);
131+
}}
132+
>
133+
Scroll To remove
134+
</button>
135+
136+
{!destroy && (
137+
<List
138+
ref={listRef}
139+
data={data}
140+
height={200}
141+
itemHeight={30}
142+
itemKey="id"
143+
style={{
144+
border: '1px solid red',
145+
boxSizing: 'border-box',
146+
}}
147+
>
148+
{(item, _, props) =>
149+
type === 'dom' ? (
150+
<ForwardMyItem {...item} {...props} />
151+
) : (
152+
<TestItem {...item} {...props} />
153+
)
154+
}
155+
</List>
156+
)}
141157
</div>
142158
</React.StrictMode>
143159
);

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@
4242
"react-dom": "*"
4343
},
4444
"devDependencies": {
45+
"@types/classnames": "^2.2.10",
46+
"@types/enzyme": "^3.10.5",
4547
"@types/jest": "^25.1.3",
48+
"@types/raf": "^3.4.0",
4649
"@types/react": "^16.8.19",
4750
"@types/react-dom": "^16.8.4",
4851
"@types/warning": "^3.0.0",

src/List.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ class List<T = any> extends React.Component<ListProps<T>, ListState<T>> {
132132
data: [],
133133
};
134134

135+
rafId: number;
136+
135137
listRef = React.createRef<HTMLElement>();
136138

137139
itemElements: { [index: number]: HTMLElement } = {};
@@ -376,6 +378,10 @@ class List<T = any> extends React.Component<ListProps<T>, ListState<T>> {
376378
this.cachedProps = this.props;
377379
}
378380

381+
componentWillUnmount() {
382+
raf.cancel(this.rafId);
383+
}
384+
379385
/**
380386
* Phase 2: Trigger render since we should re-calculate current position.
381387
*/
@@ -435,8 +441,8 @@ class List<T = any> extends React.Component<ListProps<T>, ListState<T>> {
435441
}
436442

437443
const item = data[index];
444+
/* istanbul ignore next */
438445
if (item === undefined) {
439-
/* istanbul ignore next */
440446
console.error('Not find index item. Please report this since it is a bug.');
441447
return null;
442448
}
@@ -470,7 +476,9 @@ class List<T = any> extends React.Component<ListProps<T>, ListState<T>> {
470476
};
471477

472478
public scrollTo = (arg0: number | ScrollConfig) => {
473-
raf(() => {
479+
raf.cancel(this.rafId);
480+
481+
this.rafId = raf(() => {
474482
// Number top
475483
if (typeof arg0 === 'object') {
476484
const { isVirtual } = this.state;

tests/__mocks__/raf.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1-
export default function raf(callback) {
2-
setTimeout(callback);
1+
function raf(callback) {
2+
return setTimeout(callback);
33
}
4+
5+
raf.cancel = id => {
6+
clearTimeout(id);
7+
};
8+
9+
export default raf;

tests/scroll.test.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@ describe('List.Scroll', () => {
8989
});
9090
});
9191

92+
it('not crash', () => {
93+
listRef.current.scrollTo({ ...scrollConfig, align: 'top' });
94+
wrapper.unmount();
95+
jest.runAllTimers();
96+
});
97+
9298
it('top', () => {
9399
listRef.current.scrollTo({ ...scrollConfig, align: 'top' });
94100
jest.runAllTimers();

0 commit comments

Comments
 (0)