Skip to content

Commit 56ae28c

Browse files
committedNov 21, 2017
Improve perfomance while reordering
1 parent cc03b8e commit 56ae28c

File tree

3 files changed

+172
-55
lines changed

3 files changed

+172
-55
lines changed
 

‎src/SortableList.js

+167-55
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, {Component} from 'react';
22
import PropTypes from 'prop-types';
33
import {ScrollView, View, StyleSheet, Platform, RefreshControl, ViewPropTypes} from 'react-native';
4-
import {shallowEqual, swapArrayElements} from './utils';
4+
import {inRange, shallowEqual, swapArrayElements} from './utils';
55
import Row from './Row';
66

77
const AUTOSCROLL_INTERVAL = 100;
@@ -211,22 +211,12 @@ export default class SortableList extends Component {
211211
const {horizontal, rowActivationTime, sortingEnabled, renderRow} = this.props;
212212
const {animated, order, data, activeRowKey, releasedRowKey, rowsLayouts} = this.state;
213213

214-
215-
let nextX = 0;
216-
let nextY = 0;
217-
218214
return order.map((key, index) => {
219215
const style = {[ZINDEX]: 0};
220-
const location = {x: 0, y: 0};
221-
222-
if (rowsLayouts) {
223-
if (horizontal) {
224-
location.x = nextX;
225-
nextX += rowsLayouts[key].width;
226-
} else {
227-
location.y = nextY;
228-
nextY += rowsLayouts[key].height;
229-
}
216+
let location;
217+
218+
if (rowsLayouts && rowsLayouts[key]) {
219+
location = {x: rowsLayouts[key].x, y: rowsLayouts[key].y};
230220
}
231221

232222
const active = activeRowKey === key;
@@ -279,11 +269,14 @@ export default class SortableList extends Component {
279269
}
280270

281271
_onUpdateLayouts() {
272+
const {horizontal} = this.props;
273+
const {order} = this.state;
274+
282275
Promise.all([this._footerLayout, ...Object.values(this._rowsLayouts)])
283276
.then(([footerLayout, ...rowsLayouts]) => {
284277
// Can get correct container’s layout only after rows’s layouts.
285278
this._container.measure((x, y, width, height, pageX, pageY) => {
286-
const rowsLayoutsByKey = {};
279+
let rowsLayoutsByKey = {};
287280
let contentHeight = 0;
288281
let contentWidth = 0;
289282

@@ -292,10 +285,12 @@ export default class SortableList extends Component {
292285
contentHeight += layout.height;
293286
contentWidth += layout.width;
294287
});
288+
rowsLayoutsByKey = this._getRowsLocations(rowsLayoutsByKey, order);
295289

296290
this.setState({
297291
containerLayout: {x, y, width, height, pageX, pageY},
298292
rowsLayouts: rowsLayoutsByKey,
293+
rowsSwapRanges: this._getRowsSwapRanges(rowsLayoutsByKey, order),
299294
footerLayout,
300295
contentHeight,
301296
contentWidth,
@@ -306,6 +301,54 @@ export default class SortableList extends Component {
306301
});
307302
}
308303

304+
_getRowsLocations(_rowsLayouts, order) {
305+
const {horizontal} = this.props;
306+
const rowsLayouts = {};
307+
let nextX = 0;
308+
let nextY = 0;
309+
310+
for (let i = 0, len = order.length; i < len; i++) {
311+
const rowKey = order[i];
312+
const rowLayout = _rowsLayouts[rowKey];
313+
314+
rowsLayouts[rowKey] = {
315+
...rowLayout,
316+
x: nextX,
317+
y: nextY,
318+
};
319+
320+
if (horizontal) {
321+
nextX += rowLayout.width;
322+
} else {
323+
nextY += rowLayout.height;
324+
}
325+
}
326+
327+
return rowsLayouts;
328+
}
329+
330+
_getRowsSwapRanges(rowsLayouts, order) {
331+
const {horizontal} = this.props;
332+
const rowsSwapRanges = {};
333+
334+
for (let i = 0, len = order.length; i < len; i++) {
335+
const rowKey = order[i];
336+
const rowLayout = rowsLayouts[rowKey];
337+
338+
rowsSwapRanges[rowKey] = horizontal
339+
? {
340+
left: [rowLayout.x + rowLayout.width / 3, rowLayout.x + rowLayout.width],
341+
right: [rowLayout.x, rowLayout.x + 2 * rowLayout.width / 3],
342+
}
343+
: {
344+
top: [rowLayout.y + rowLayout.height / 3, rowLayout.y + rowLayout.height],
345+
bottom: [rowLayout.y, rowLayout.y + 2 * rowLayout.height / 3],
346+
};
347+
}
348+
349+
return rowsSwapRanges;
350+
}
351+
309352
_scroll(animated) {
310353
this._scrollView.scrollTo({...this._contentOffset, animated});
311354
}
@@ -315,7 +358,8 @@ export default class SortableList extends Component {
315358
* swaps them, else shifts rows.
316359
*/
317360
_setOrderOnMove() {
318-
const {activeRowKey, activeRowIndex, order} = this.state;
361+
const {activeRowKey, activeRowIndex, order, rowsLayouts} = this.state;
362+
const {horizontal} = this.props;
319363

320364
if (activeRowKey === null || this._autoScrollInterval) {
321365
return;
@@ -345,9 +389,14 @@ export default class SortableList extends Component {
345389
nextOrder.splice(rowUnderActiveIndex, 0, activeRowKey);
346390
}
347391

392+
const nextRowsLayouts = this._getRowsLocations(rowsLayouts, nextOrder);
393+
const nextRowsSwapRanges = this._getRowsSwapRanges(nextRowsLayouts, nextOrder);
394+
348395
this.setState({
349396
order: nextOrder,
350397
activeRowIndex: rowUnderActiveIndex,
398+
rowsLayouts: nextRowsLayouts,
399+
rowsSwapRanges: nextRowsSwapRanges,
351400
}, () => {
352401
if (this.props.onChangeOrder) {
353402
this.props.onChangeOrder(nextOrder);
@@ -357,53 +406,114 @@ export default class SortableList extends Component {
357406
}
358407

359408
/**
360-
* Finds a row, which was covered with the moving row’s half.
409+
* Finds a row, which was covered with the moving row’s third.
361410
*/
362411
_findRowUnderActiveRow() {
363412
const {horizontal} = this.props;
364-
const {rowsLayouts, activeRowKey, activeRowIndex, order} = this.state;
365-
const movingRowLayout = rowsLayouts[activeRowKey];
366-
const rowLeftX = this._activeRowLocation.x
367-
const rowRightX = rowLeftX + movingRowLayout.width;
368-
const rowTopY = this._activeRowLocation.y;
369-
const rowBottomY = rowTopY + movingRowLayout.height;
370-
371-
for (
372-
let currentRowIndex = 0, x = 0, y = 0, rowsCount = order.length;
373-
currentRowIndex < rowsCount - 1;
374-
currentRowIndex++
413+
const {rowsLayouts, rowsSwapRanges, activeRowKey, activeRowIndex, order} = this.state;
414+
const movingDirection = this._movingDirection;
415+
const rowsCount = order.length;
416+
const activeRowLayout = rowsLayouts[activeRowKey];
417+
const activeRowLeftX = this._activeRowLocation.x
418+
const activeRowRightX = this._activeRowLocation.x + activeRowLayout.width;
419+
const activeRowTopY = this._activeRowLocation.y;
420+
const activeRowBottomY = this._activeRowLocation.y + activeRowLayout.height;
421+
422+
const prevRowIndex = activeRowIndex - 1;
423+
const prevRowKey = order[prevRowIndex];
424+
const prevRowSwapRages = rowsSwapRanges[prevRowKey]
425+
const nextRowIndex = activeRowIndex + 1;
426+
const nextRowKey = order[nextRowIndex];
427+
const nextRowSwapRages = rowsSwapRanges[nextRowKey]
428+
429+
if (horizontal
430+
? (movingDirection === 1
431+
? (
432+
(activeRowIndex === 0 || activeRowLeftX > prevRowSwapRages.right[0]) &&
433+
(activeRowIndex === rowsCount - 1 || activeRowRightX < nextRowSwapRages.left[0])
434+
)
435+
: (
436+
(activeRowIndex === 0 || activeRowLeftX > prevRowSwapRages.right[1]) &&
437+
(activeRowIndex === rowsCount - 1 || activeRowRightX < nextRowSwapRages.left[1])
438+
)
439+
)
440+
: (movingDirection === 1
441+
? (
442+
(activeRowIndex === 0 || activeRowTopY > prevRowSwapRages.bottom[0]) &&
443+
(activeRowIndex === rowsCount - 1 || activeRowBottomY < nextRowSwapRages.top[0])
444+
)
445+
: (
446+
(activeRowIndex === 0 || activeRowTopY > prevRowSwapRages.bottom[1]) &&
447+
(activeRowIndex === rowsCount - 1 || activeRowBottomY < nextRowSwapRages.top[1])
448+
)
449+
)
375450
) {
376-
const currentRowKey = order[currentRowIndex];
377-
const currentRowLayout = rowsLayouts[currentRowKey];
378-
const nextRowIndex = currentRowIndex + 1;
379-
const nextRowLayout = rowsLayouts[order[nextRowIndex]];
380-
381-
x += currentRowLayout.width;
382-
y += currentRowLayout.height;
383-
384-
if (currentRowKey !== activeRowKey && (
385-
horizontal
386-
? ((x - currentRowLayout.width <= rowLeftX || currentRowIndex === 0) && rowLeftX <= x - currentRowLayout.width / 3)
387-
: ((y - currentRowLayout.height <= rowTopY || currentRowIndex === 0) && rowTopY <= y - currentRowLayout.height / 3)
388-
)) {
389-
return {
390-
rowKey: order[currentRowIndex],
391-
rowIndex: currentRowIndex,
392-
};
393-
}
451+
return {
452+
rowKey: activeRowKey,
453+
rowIndex: activeRowIndex,
454+
};
455+
}
394456

457+
if (movingDirection === 1) {
395458
if (horizontal
396-
? (x + nextRowLayout.width / 3 <= rowRightX && (rowRightX <= x + nextRowLayout.width || nextRowIndex === rowsCount - 1))
397-
: (y + nextRowLayout.height / 3 <= rowBottomY && (rowBottomY <= y + nextRowLayout.height || nextRowIndex === rowsCount - 1))
459+
? inRange(activeRowRightX, ...nextRowSwapRages.left)
460+
: inRange(activeRowBottomY, ...nextRowSwapRages.top)
398461
) {
399-
return {
400-
rowKey: order[nextRowIndex],
462+
return {
463+
rowKey: nextRowKey,
401464
rowIndex: nextRowIndex,
402465
};
403466
}
467+
} else {
468+
if (horizontal
469+
? inRange(activeRowLeftX, ...prevRowSwapRages.right)
470+
: inRange(activeRowTopY, ...prevRowSwapRages.bottom)
471+
) {
472+
return {
473+
rowKey: prevRowKey,
474+
rowIndex: prevRowIndex,
475+
};
476+
}
404477
}
405478

406-
return {rowKey: activeRowKey, rowIndex: activeRowIndex};
479+
// let startIndex = 0;
480+
// let endIndex = rowsCount - 1;
481+
// let middleIndex;
482+
// let it = 0
483+
// console.log(movingDirection);
484+
// while (startIndex < endIndex) {
485+
// middleIndex = Math.floor((endIndex - startIndex) / 2);
486+
487+
// if (it++ > 10) {
488+
// console.log(startIndex, middleIndex, endIndex);
489+
// break
490+
// }
491+
// const middleRowSwapRanges = rowsSwapRanges[middleIndex];
492+
493+
// if (horizontal) {
494+
// if (movingDirection === 1) {
495+
// if (inRange(activeRowRightX, ...middleRowSwapRanges.left)) break;
496+
// else if (activeRowRightX < middleRowSwapRanges.left[0]) endIndex = middleIndex;
497+
// else if (activeRowRightX > middleRowSwapRanges.left[1]) startIndex = middleIndex;
498+
// } else {
499+
// if (inRange(activeRowLeftX, ...middleRowSwapRanges.right)) break;
500+
// else if (activeRowLeftX < middleRowSwapRanges.right[0]) endIndex = middleIndex;
501+
// else if (activeRowLeftX > middleRowSwapRanges.right[1]) startIndex = middleIndex;
502+
// }
503+
// } else {
504+
// if (movingDirection === 1) {
505+
// if (inRange(activeRowBottomY, ...middleRowSwapRanges.top)) break;
506+
// else if (activeRowBottomY < middleRowSwapRanges.top[0]) endIndex = middleIndex;
507+
// else if (activeRowBottomY > middleRowSwapRanges.top[1]) startIndex = middleIndex;
508+
// } else {
509+
// if (inRange(activeRowTopY, ...middleRowSwapRanges.bottom)) break;
510+
// else if (activeRowTopY < middleRowSwapRanges.bottom[0]) endIndex = middleIndex;
511+
// else if (activeRowTopY > middleRowSwapRanges.bottom[1]) startIndex = middleIndex;
512+
// }
513+
// }
514+
// }
515+
516+
// return {rowKey: order[middleIndex], rowIndex: middleIndex};
407517
}
408518

409519
_scrollOnMove(e) {
@@ -567,9 +677,11 @@ export default class SortableList extends Component {
567677
const prevMovingDirection = this._movingDirection;
568678

569679
this._activeRowLocation = location;
570-
this._movingDirection = this.props.horizontal
571-
? prevMovingRowX < this._activeRowLocation.x
572-
: prevMovingRowY < this._activeRowLocation.y;
680+
this._movingDirection = (
681+
this.props.horizontal
682+
? prevMovingRowX <= this._activeRowLocation.x
683+
: prevMovingRowY <= this._activeRowLocation.y
684+
) ? 1 : -1;
573685

574686
this._movingDirectionChanged = prevMovingDirection !== this._movingDirection;
575687
this._setOrderOnMove();

‎src/utils/inRange.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function inRange(number, start, end) {
2+
return start <= number && number <= end;
3+
}

‎src/utils/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import inRange from './inRange';
12
import shallowEqual from './shallowEqual';
23
import swapArrayElements from './swapArrayElements';
34

45
export {
6+
inRange,
57
shallowEqual,
68
swapArrayElements
79
};

0 commit comments

Comments
 (0)
Failed to load comments.