Skip to content

Commit d246cb8

Browse files
committed
fix flicker, simplify
1 parent 1e5f5b5 commit d246cb8

File tree

4 files changed

+39
-72
lines changed

4 files changed

+39
-72
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-draggable-flatlist",
3-
"version": "4.0.0-beta.5",
3+
"version": "4.0.0-beta.7",
44
"description": "A drag-and-drop-enabled FlatList component for React Native",
55
"main": "lib/commonjs/index",
66
"module": "lib/module/index",

src/components/CellRendererComponent.tsx

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,6 @@ type Props<T> = {
2929
function CellRendererComponent<T>(props: Props<T>) {
3030
const { item, index, onLayout, children, ...rest } = props;
3131

32-
const currentIndexAnim = useSharedValue(index);
33-
34-
useEffect(() => {
35-
// If we set the index immediately the newly-ordered data can get out of sync
36-
// with the activeIndexAnim, and cause the wrong item to momentarily become the
37-
// "active item", which causes a flicker.
38-
requestAnimationFrame(() => {
39-
currentIndexAnim.value = index;
40-
});
41-
}, [index]);
42-
4332
const viewRef = useRef<Animated.View>(null);
4433
const { cellDataRef, propsRef, containerRef } = useRefs<T>();
4534

@@ -57,26 +46,20 @@ function CellRendererComponent<T>(props: Props<T>) {
5746
const translate = useCellTranslate({
5847
cellOffset: offset,
5948
cellSize: size,
60-
cellIndex: currentIndexAnim,
49+
cellIndex: index,
6150
});
6251

63-
const indexRef = useRef(index);
64-
const indexHasChanged = index !== indexRef.current;
65-
indexRef.current = index;
66-
67-
const dragInProgress = !!activeKey && !indexHasChanged;
68-
const isActive = dragInProgress && activeKey === key;
52+
const isActive = activeKey === key;
6953

7054
const animStyle = useAnimatedStyle(() => {
71-
const _translate = dragInProgress ? translate.value : 0;
7255
return {
7356
transform: [
7457
horizontalAnim.value
75-
? { translateX: _translate }
76-
: { translateY: _translate },
58+
? { translateX: translate.value }
59+
: { translateY: translate.value },
7760
],
7861
};
79-
}, [dragInProgress, translate]);
62+
}, [translate]);
8063

8164
const updateCellMeasurements = useStableCallback(() => {
8265
const onSuccess: MeasureLayoutOnSuccessCallback = (x, y, w, h) => {
@@ -107,19 +90,19 @@ function CellRendererComponent<T>(props: Props<T>) {
10790
}
10891
});
10992

93+
const onCellLayout = useStableCallback((e?: LayoutChangeEvent) => {
94+
updateCellMeasurements();
95+
if (onLayout && e) onLayout(e);
96+
});
97+
11098
useEffect(() => {
11199
if (isWeb) {
112100
// onLayout isn't called on web when the cell index changes, so we manually re-measure
113101
requestAnimationFrame(() => {
114-
updateCellMeasurements();
102+
onCellLayout();
115103
});
116104
}
117-
}, [index, updateCellMeasurements]);
118-
119-
const onCellLayout = useStableCallback((e: LayoutChangeEvent) => {
120-
updateCellMeasurements();
121-
if (onLayout) onLayout(e);
122-
});
105+
}, [index, onCellLayout]);
123106

124107
const baseStyle = useMemo(() => {
125108
return {
@@ -137,11 +120,7 @@ function CellRendererComponent<T>(props: Props<T>) {
137120
{...rest}
138121
ref={viewRef}
139122
onLayout={onCellLayout}
140-
style={[
141-
props.style,
142-
baseStyle,
143-
dragInProgress ? animStyle : { transform: [] },
144-
]}
123+
style={[props.style, baseStyle, animStyle]}
145124
pointerEvents={activeKey ? "none" : "auto"}
146125
>
147126
<CellProvider isActive={isActive}>{children}</CellProvider>

src/components/DraggableFlatList.tsx

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Animated, {
1313
withSpring,
1414
} from "react-native-reanimated";
1515
import CellRendererComponent from "./CellRendererComponent";
16-
import { DEFAULT_PROPS, isWeb } from "../constants";
16+
import { DEFAULT_PROPS } from "../constants";
1717
import PlaceholderItem from "./PlaceholderItem";
1818
import RowItem from "./RowItem";
1919
import { DraggableFlatListProps } from "../types";
@@ -87,17 +87,6 @@ function DraggableFlatListInner<T>(props: DraggableFlatListProps<T>) {
8787
});
8888
}, [props.data, keyExtractor, keyToIndexRef]);
8989

90-
// Reset hover state whenever data changes
91-
useMemo(() => {
92-
requestAnimationFrame(() => {
93-
activeIndexAnim.value = -1;
94-
spacerIndexAnim.value = -1;
95-
touchTranslate.value = 0;
96-
activeCellSize.value = -1;
97-
activeCellOffset.value = -1;
98-
});
99-
}, [props.data]);
100-
10190
const drag = useStableCallback((activeKey: string) => {
10291
if (disabled.value) return;
10392
const index = keyToIndexRef.current.get(activeKey);
@@ -181,15 +170,15 @@ function DraggableFlatListInner<T>(props: DraggableFlatListProps<T>) {
181170
newData.splice(from, 1);
182171
newData.splice(to, 0, data[from]);
183172
}
184-
onDragEnd({ from, to, data: newData });
185-
if (isWeb) {
186-
// prevent flicker
173+
setTimeout(() => {
174+
activeIndexAnim.value = -1;
175+
spacerIndexAnim.value = -1;
176+
touchTranslate.value = 0;
177+
activeCellSize.value = -1;
178+
activeCellOffset.value = -1;
187179
setActiveKey(null);
188-
} else {
189-
requestAnimationFrame(() => {
190-
setActiveKey(null);
191-
});
192-
}
180+
});
181+
onDragEnd({ from, to, data: newData });
193182
}
194183
}
195184
);
@@ -266,7 +255,7 @@ function DraggableFlatListInner<T>(props: DraggableFlatListProps<T>) {
266255
runOnJS(onContainerTouchEnd)();
267256
});
268257

269-
if (props.hitSlop) panGesture.hitSlop(props.hitSlop);
258+
if (dragHitSlop) panGesture.hitSlop(dragHitSlop);
270259
if (activationDistanceProp) {
271260
const activeOffset = [-activationDistanceProp, activationDistanceProp];
272261
if (props.horizontal) {

src/hooks/useCellTranslate.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useDraggableFlatListContext } from "../context/draggableFlatListContext
44
import { useRefs } from "../context/refContext";
55

66
type Params = {
7-
cellIndex: Animated.SharedValue<number>;
7+
cellIndex: number;
88
cellSize: Animated.SharedValue<number>;
99
cellOffset: Animated.SharedValue<number>;
1010
};
@@ -19,16 +19,16 @@ export function useCellTranslate({ cellIndex, cellSize, cellOffset }: Params) {
1919
hoverAnim,
2020
} = useAnimatedValues();
2121

22-
const { activeKey } = useDraggableFlatListContext()
22+
const { activeKey } = useDraggableFlatListContext();
2323

2424
const { animationConfigRef } = useRefs();
2525

2626
const translate = useDerivedValue(() => {
27-
if (!activeKey || activeIndexAnim.value < 0) return 0
27+
if (!activeKey || activeIndexAnim.value < 0) return 0;
2828

2929
// Determining spacer index is hard to visualize. See diagram: https://i.imgur.com/jRPf5t3.jpg
30-
const isBeforeActive = cellIndex.value < activeIndexAnim.value;
31-
const isAfterActive = cellIndex.value > activeIndexAnim.value;
30+
const isBeforeActive = cellIndex < activeIndexAnim.value;
31+
const isAfterActive = cellIndex > activeIndexAnim.value;
3232

3333
const hoverPlusActiveSize = hoverOffset.value + activeCellSize.value;
3434
const offsetPlusHalfSize = cellOffset.value + cellSize.value / 2;
@@ -41,35 +41,35 @@ export function useCellTranslate({ cellIndex, cellSize, cellOffset }: Params) {
4141
hoverPlusActiveSize < offsetPlusHalfSize
4242
) {
4343
// bottom edge of active cell overlaps top half of current cell
44-
result = cellIndex.value - 1;
44+
result = cellIndex - 1;
4545
} else if (
4646
hoverPlusActiveSize >= offsetPlusHalfSize &&
4747
hoverPlusActiveSize < offsetPlusSize
4848
) {
4949
// bottom edge of active cell overlaps bottom half of current cell
50-
result = cellIndex.value;
50+
result = cellIndex;
5151
}
5252
} else if (isBeforeActive) {
5353
if (
5454
hoverOffset.value < offsetPlusSize &&
5555
hoverOffset.value >= offsetPlusHalfSize
5656
) {
5757
// top edge of active cell overlaps bottom half of current cell
58-
result = cellIndex.value + 1;
58+
result = cellIndex + 1;
5959
} else if (
6060
hoverOffset.value >= cellOffset.value &&
6161
hoverOffset.value < offsetPlusHalfSize
6262
) {
6363
// top edge of active cell overlaps top half of current cell
64-
result = cellIndex.value;
64+
result = cellIndex;
6565
}
6666
}
6767

6868
if (result !== -1 && result !== spacerIndexAnim.value) {
6969
spacerIndexAnim.value = result;
7070
}
7171

72-
if (spacerIndexAnim.value === cellIndex.value) {
72+
if (spacerIndexAnim.value === cellIndex) {
7373
const newPlaceholderOffset = isAfterActive
7474
? cellSize.value + (cellOffset.value - activeCellSize.value)
7575
: cellOffset.value;
@@ -80,16 +80,16 @@ export function useCellTranslate({ cellIndex, cellSize, cellOffset }: Params) {
8080
if (activeIndexAnim.value < 0) return 0;
8181

8282
// Active cell follows touch
83-
if (cellIndex.value === activeIndexAnim.value) {
84-
return hoverAnim.value
85-
};
83+
if (cellIndex === activeIndexAnim.value) {
84+
return hoverAnim.value;
85+
}
8686

8787
// Translate cell down if it is before active index and active cell has passed it.
8888
// Translate cell up if it is after the active index and active cell has passed it.
8989

9090
const shouldTranslate = isAfterActive
91-
? cellIndex.value <= spacerIndexAnim.value
92-
: cellIndex.value >= spacerIndexAnim.value;
91+
? cellIndex <= spacerIndexAnim.value
92+
: cellIndex >= spacerIndexAnim.value;
9393

9494
const translationAmt = shouldTranslate
9595
? activeCellSize.value * (isAfterActive ? -1 : 1)
@@ -98,6 +98,5 @@ export function useCellTranslate({ cellIndex, cellSize, cellOffset }: Params) {
9898
return withSpring(translationAmt, animationConfigRef.current);
9999
}, [activeKey]);
100100

101-
102101
return translate;
103102
}

0 commit comments

Comments
 (0)