Skip to content

Visual glitch: Item briefly returns to original position before settling in new position after drag #114

@YuraZakaryan

Description

@YuraZakaryan

Description

When dragging and dropping an item to reorder it, there's a visual glitch where the item briefly "jumps" back to its original position before settling into the new position. This creates a jarring user experience.

Expected Behavior

When I drop an item at a new position, it should smoothly stay in that position without any visual jump or animation back to the original position.

Actual Behavior

  1. User drags an item from position A to position B
  2. User releases the item at position B
  3. The item briefly animates/jumps back to position A
  4. Then the item appears at position B (the correct final position)

Environment

  • react-native-draglist version: 3.10.0
  • React Native version: 0.81.4
  • Platform: iOS and Android

Code Example

import React, { useCallback, useMemo } from 'react';
import { View, Text } from 'react-native';
import DragList from 'react-native-draglist';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
import { setCategoryReordering } from '../../../store/reducer/mediaSlice';

function Content({ screen }) {
  const dispatch = useAppDispatch();

  const state = useAppSelector(state => state.media.mediaData.movie);

  const data = useMemo(() => {
    if (!state?.keys?.length) {
      return [];
    }

    return state.keys.reduce((acc, key) => {
      const hasContents =
        Array.isArray(state[key]?.contents) && state[key].contents.length > 0;
      const isRejected = rejectedKeys.includes(key);
      const info = state[key]?.category_info;

      if (!hasContents || isRejected || !info) {
        return acc;
      }

      acc.push({
        id: info.category_id,
        category_name: info.category_name,
        category_id: info.category_id,
        count: state[key].contents.length,
      });

      return acc;
    }, []);
  }, [state, rejectedKeys]);

  const onReordered = useCallback(
    async (fromIndex, toIndex) => {
      const copy = [...data];
      const [movedItem] = copy.splice(fromIndex, 1);
      copy.splice(toIndex, 0, movedItem);

      const updatedState = [
        ...rejectedKeys,
        ...copy.map(item => item.category_id),
      ];

      dispatch(
        setCategoryReordering({
          mediaType: 'movie',
          orderedKeys: updatedState,
        }),
      );
    },
    [data, rejectedKeys, dispatch],
  );

  const renderItem = useCallback(
    ({ item, onDragStart, onDragEnd, isActive }) => {
      return (
        <TouchableOpacity
        activeOpacity={0.8}
        onPress={onPress}
        onLongPress={onDragStart}
        onPressOut={onDragEnd}
        delayLongPress={200}
      >
        <View style={styles.categoryBtnContent}>
          <Text style={styles.categoryName} numberOfLines={1}>
            {displayText}
          </Text>
          <SIX_POIN_ICON color={APP_DEFAULT_BRANDING.white} />
        </View>
      </TouchableOpacity>
      );
    },
    [],
  );

  const keyExtractor = useCallback(item => item?.category_id?.toString(), []);

  return (
    <DragList
      data={data}
      keyExtractor={keyExtractor}
      renderItem={renderItem}
      onReordered={onReordered}
      showsVerticalScrollIndicator={false}
    />
  );
}

Video Demonstration

https://drive.google.com/file/d/11j5Mvtlq-wgVgJUAxGU4RNDkqSA2QL1Z/view?usp=sharing

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions