Implement a Sortable List Component in React
Build a reusable React component that displays a list of items, allowing users to reorder them by dragging and dropping. This is a common feature in many user interfaces, enabling users to personalize content order or manage tasks.
Problem Description
Your task is to create a React component named SortableList that accepts an array of data objects and renders them as a list. Users should be able to interact with this list by dragging individual list items to new positions within the list. The component should visually indicate when an item is being dragged and where it will be dropped. Upon dropping an item, the underlying data array should be updated to reflect the new order.
Key Requirements:
- Display List Items: Render each item in the provided data array. Each item should be a distinct visual element (e.g., a
divorli). - Drag and Drop Functionality: Implement drag and drop interactions for reordering.
- Items should be draggable.
- Users should be able to drop items into different positions within the same list.
- Visual Feedback: Provide clear visual cues to the user:
- When an item is being dragged (e.g., change background color, add a shadow).
- Indicate the potential drop target area (e.g., a border or highlight where the item will land).
- State Management: The component must manage its internal state, updating the order of the data array when a drag-and-drop operation is completed.
- Callback for Order Change: The
SortableListcomponent should accept anonOrderChangeprop, a callback function that is invoked with the new, reordered array whenever the list order is modified.
Expected Behavior:
When a user clicks and holds an item, it becomes draggable. As the user moves the item over other items, the list should dynamically adjust to show where the item would be placed. Upon releasing the mouse button, the item settles into its new position, and the onOrderChange callback is triggered with the updated list data.
Edge Cases to Consider:
- An empty list.
- A list with a single item.
- Dragging an item to its original position.
Examples
Example 1:
Input Data:
[
{"id": 1, "text": "Task A"},
{"id": 2, "text": "Task B"},
{"id": 3, "text": "Task C"}
]
User Action: Drag "Task B" and drop it between "Task A" and "Task C".
Output Data (passed to onOrderChange):
[
{"id": 1, "text": "Task A"},
{"id": 2, "text": "Task B"},
{"id": 3, "text": "Task C"}
]
Explanation: The original order was A, B, C. After dragging B to between A and C, the order becomes A, B, C (no change in this specific case, but the mechanism should handle it).
Example 2:
Input Data:
[
{"id": 1, "text": "Item One"},
{"id": 2, "text": "Item Two"},
{"id": 3, "text": "Item Three"}
]
User Action: Drag "Item Three" and drop it at the very beginning of the list.
Output Data (passed to onOrderChange):
[
{"id": 3, "text": "Item Three"},
{"id": 1, "text": "Item One"},
{"id": 2, "text": "Item Two"}
]
Explanation: The original order was One, Two, Three. Dragging Three to the top results in the new order: Three, One, Two.
Constraints
- The input
dataprop will be an array of objects, where each object has at least a uniqueidproperty and another property (e.g.,text) to display. - The component should be built using TypeScript and React functional components.
- The implementation should aim for reasonable performance, especially for lists of moderate size (up to 50 items). Avoid overly complex DOM manipulations within the drag events if possible.
- Styling can be achieved using inline styles, CSS modules, or a CSS-in-JS library. The primary focus is on functionality.
Notes
- You are free to choose a drag-and-drop library (like
react-beautiful-dnd,dnd-kit, or even implement it using native HTML Drag and Drop API) or implement the logic from scratch. However, using a well-established library is often recommended for robustness and accessibility. - Consider how to handle
keyprops correctly for efficient rendering in React. - The
onOrderChangecallback is crucial for enabling parent components to react to changes in the list's order. - Ensure the visual feedback for dragging and dropping is intuitive and guides the user.