【问题标题】:Why is updating state not causing a re-render (updating state using drag and drop)?为什么更新状态不会导致重新渲染(使用拖放更新状态)?
【发布时间】:2021-02-01 15:38:22
【问题描述】:

我正在制作一个可以使用拖放交换卡片的卡片系统。当我将卡片相互拖动时,我的状态正在按预期更新,但不会重新渲染。

import React, {useRef, useState} from 'react';
import DnDGroup from './DndGroup';

const DragNDrop = ({data}) => {
  const [list, setList] = useState(data);

  const dragItem = useRef();
  const dragNode = useRef();

  const getParams = (element) => {
    const itemNum = element.toString();
    const group = list.find(group => group.items.find(item => item === itemNum))
    const groupIndex = list.indexOf(group);
    const itemIndex = group.items.indexOf(itemNum);
    return {'groupIndex': groupIndex, 'itemIndex': itemIndex}
  }

  const handleDragstart = (e) => {
    dragNode.current = e.target;
    setTimeout(() => {
      dragNode.current.classList.add('current')
    }, 0)    
    dragItem.current = getParams(e.target.value);

    dragNode.current.addEventListener('dragend', () => {
      if(dragNode.current !== undefined) {
        dragNode.current.classList.remove('current')
      } 
    })
  }

  const handleDragEnter = e => {
    if(dragNode.current !== e.target && e.target.value !== undefined) {
      const node = getParams(e.target.value);
      const currentItem = dragItem.current;
      [data[currentItem.groupIndex].items[currentItem.itemIndex], data[node.groupIndex].items[node.itemIndex]] = [data[node.groupIndex].items[node.itemIndex], data[currentItem.groupIndex].items[currentItem.itemIndex]];
      setList(data);
      console.log(list)
    } 
  } 

    return (
    <div className='drag-n-drop'>
      {list.map(group => (
        <DnDGroup 
          key={group.title} 
          group={group} 
          handleDragstart={handleDragstart}
          handleDragEnter={handleDragEnter}
        />
      ))}
        </div>
    );
};

export default DragNDrop;

我也尝试过这样做:

setList([...data])

使用它可以根据状态变化进行渲染,并且在一个组内效果很好,但是当我想将一张卡片拖到另一个组时,状态会像疯了一样不断地来回变化,它也会产生大量的 console.logs .

我该如何解决这个问题?

【问题讨论】:

  • 因为您正在改变前一行中的状态。永远不要在 React 中改变状态。
  • 如何使用当前状态进行更新?

标签: reactjs drag-and-drop state


【解决方案1】:

用这一行:

[data[currentItem.groupIndex].items[currentItem.itemIndex], data[node.groupIndex].items[node.itemIndex]] = [data[node.groupIndex].items[node.itemIndex], data[currentItem.groupIndex].items[currentItem.itemIndex]];

您正在改变data 数组中的一个深层嵌套对象。永远不要在 React 中改变状态;除了其他意想不到的(和不希望的)副作用之外,它还可能导致组件无法按照您的预期重新渲染。

另一件看起来可能无意的错误是您正在更改 data(原始状态)而不是有状态的 list 数组。

改成:

const itemA = list[node.groupIndex].items[node.itemIndex];
const itemB = list[currentItem.groupIndex].items[currentItem.itemIndex];
const newList = [...list];
newList[currentItem.groupIndex] = {
    ...newList[currentItem.groupIndex],
    items: newList[currentItem.groupIndex].map(
        (item, i) => i !== currentItem.itemIndex ? item : itemB
    )
};
newList[node.groupIndex] = {
    ...newList[node.groupIndex],
    items: newList[node.groupIndex].map(
        (item, i) => i !== node.itemIndex ? item : itemA
    )
};
setList(newList);

这避免了嵌套items子数组的突变。

【讨论】:

  • 我尝试使用它,但它不起作用。为了使地图功能正常工作,我必须在映射之前添加“项目”。但这并没有改变该州的任何事情。接下来我切换了 itemA 和 itemB,但如果这样做,我会遇到与使用自己的代码相同的问题。
猜你喜欢
  • 2022-12-21
  • 1970-01-01
  • 2019-05-07
  • 2020-11-04
  • 1970-01-01
  • 2015-11-03
  • 2019-06-17
  • 1970-01-01
  • 2016-11-04
相关资源
最近更新 更多