React中使用dragula拖拽到新容器后数据不同步怎么办?
我在用dragula实现两个列表之间的拖拽功能,但把元素拖到另一个容器后,状态里的数据没跟着更新,卡了好久
代码是这样的:
import { dragula } from 'dragula';
function ListContainer() {
const [items, setItems] = useState([]);
const [targetItems, setTargetItems] = useState([]);
useEffect(() => {
const bag = dragula([document.getElementById('list1'), document.getElementById('list2')]);
return () => bag.destroy();
}, []);
return (
<div>
<div id="list1">{items.map(item => <div key={item.id}>{item.name}</div>)}</div>
<div id="list2">{targetItems.map(item => <div key={item.id}>{item.name}</div>)}</div>
</div>
);
}
我已经尝试在dragula实例里加drop事件监听,但修改状态时发现新旧元素数据拿不到,控制台也没报错,求大神指点
要解决这个问题,我们需要手动监听dragula的事件,并在事件回调中同步React的状态。下面是具体的解决方案:
首先,在初始化dragula的时候,添加对
drop事件的监听。这个事件会在元素被拖拽到新容器并放置后触发。通过这个事件,我们可以拿到拖拽的元素、源容器和目标容器的信息。然后,根据这些信息手动更新React的状态。我们需要把源容器和目标容器的数据重新计算一遍,并用
setItems和setTargetItems来更新状态。来看代码实现:
详细说明
1. 数据标识:为了让React能够正确识别每个元素,我们在渲染的时候给每个元素加了一个
data-id属性,值是元素的唯一id。这样在drop事件里可以通过el.dataset.id拿到对应的id。2. 状态更新逻辑:根据源容器和目标容器的id判断拖拽的方向,然后分别处理两种情况:
- 从
list1拖到list2:从items中移除对应元素,并将其添加到targetItems。- 从
list2拖回list1:从targetItems中移除对应元素,并将其添加回items。3. 依赖项问题:
useEffect的依赖数组里需要包含items和targetItems,否则在状态更新后,事件回调里的数据会是旧的,导致状态不同步。4. 性能优化:虽然这里直接用了
find和filter来操作数组,但如果数据量特别大,可以考虑用Map或其他数据结构优化查找和更新的性能。这样做之后,React的状态就会和DOM保持同步了。不过说实话,dragula这种库其实更适合纯DOM操作的场景,如果你完全用React生态的话,建议可以看看像
react-dnd这样的库,它们天生就和React的状态管理更契合。