首页 > 解决方案 > 如何在不手动重建的情况下复制和渲染 React 元素?

问题描述

我正在尝试创建一个非常简单的拖放组件,并且我认为只需通过onDrop事件构建一个数组,只需将其添加event.target就足够了,但似乎 React 不喜欢这样。它在渲染时给我错误“对象作为 React 子项无效”,如果我在添加到数组之前尝试克隆元素,我会得到“元素类型无效:需要一个字符串(对于内置组件)或类/函数(用于复合组件)但得到:未定义”。

我四处搜索,几乎我一直看到的类似问题的唯一建议是基本上用最初使用的任何道具重建元素。如果元素类型/道具/等是已知的并且总是相同的,这一切都很好,但如果不是呢?是否有更灵活的解决方案来复制您可能不知道它最初是如何构造的元素?

这是我的代码现在的样子:

import React from 'react'
import ReactDOM from 'react-dom'

function Draggable(props) {
  return <div draggable={true} onDragStart={props.onDragStart}>{props.children}</div>
}

function Droppable(props) {
  return <div onDragOver={props.onDragOver} onDrop={props.onDrop} className="droppable">{props.children}</div>
}

export default function App() {
  const [draggedElement, setDraggedElement] = React.useState(null)
  const [droppedElements, setDroppedElements] = React.useState([])

  function onDragStart(e) {
    setDraggedElement(e.target);
  }

  function onDragOver(e) {
    e.preventDefault();
  }

  function onDrop(e) {
    e.preventDefault();
    setDroppedElements([...droppedElements, React.cloneElement(draggedElement, {key: 'test'})]);
  }

  return (
    <React.Fragment>
      <Draggable onDragStart={onDragStart}>draggable</Draggable>
      <Droppable onDragOver={onDragOver} onDrop={onDrop}>{droppedElements}</Droppable>
    </React.Fragment>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

标签: javascriptreactjs

解决方案


您可以使用 e.dataTransfer.setData() 和 e.dataTransfer.getData() 来更好地传输数据。这是我使用可拖动卡片组件所做的项目示例:

const dragStart = e => {
        // e.preventDefault();
        console.log("in dragStart");
        const target = e.target;

        e.dataTransfer.setData('card_id', target.id);

const drop = e => {
        console.log("Here in first drop function");
        e.preventDefault();
        const card_id = e.dataTransfer.getData('card_id');
        const card = document.getElementById(card_id);

然后将卡片放到某个东西上,在 drop 函数中,您可以使用 e.target.append() 将从 e.dataTransfer.getData 元素中获得的数据放到 e.target 中。

e.target.appendChild(card);

所以在这种情况下,e.target.appendChild(card) 中的“卡片”只是使用 e.dataTransfer.setData() 在 dragStart 函数中设置的数据。如果这是有道理的。


推荐阅读