有了react DnD,为什么每次我放下一个元素时我的状态都会重置



我正在开发一个表单生成器。基本的实现是可行的,但每次我将元素从工具箱移动到表单时,当前状态都会重置为初始状态,然后添加新删除的元素,这样以前拖动的元素就会从表单中丢失。下面是链接到沙箱源代码的链接。

https://codesandbox.io/s/nifty-https-qx8lko

index.js

import Example from "./Example.jsx";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import "./style.sass";
function App() {
return (
<div className="App">
<DndProvider backend={HTML5Backend}>
<Example />
</DndProvider>
</div>
);
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);

示例.jsx

import React, { useState } from "react";
import Form from "./Form";
import Toolbar from "./Toolbar";
const Example = (props) => {
const [Items, setItems] = useState([{ name: "Test" }]);
const addItem = (item) => {
setItems([...Items, item]);
};
return (
<div className="card" style={{ border: "1px dashed rgb(219 163 163)" }}>
<div className="card-header  d-flex justify-content-between">
<h5 className="cart-title m-0">View</h5>
</div>
<div className="card-body">
<div className="row">
<div className="col-9">
<Form items={Items} addItems={addItem} />
</div>
<div className="col-3">
<Toolbar />
</div>
</div>
</div>
</div>
);
};
export default Example;

Form.jsx

import React from "react";
import { useDrop } from "react-dnd";
import { ItemTypes } from "./ItemTypes";
function Form(props) {
const addItem = (item) => {
props.addItems(item);
};
const [{ canDrop, isOver }, drop] = useDrop(() => ({
accept: ItemTypes.CARD,
drop: (item, monitor) => addItem(item),
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
})
}));
return (
<div className="card card-default shadow-sm mt-3">
<div className="card-body">
{props.items.map((item, index) => {
return (
<div key={index} className="form-item">
{item.name}
</div>
);
})}
<div ref={drop}>
{/* {canDrop ? "Release to drop" : "Drag a box here"} */}
{isOver && canDrop && (
<div className="form-place-holder">
<div>Release to Drop</div>
</div>
)}
{!isOver && (
<div className="form-place-holder">
<div>Dropzone</div>
</div>
)}
</div>
</div>
</div>
);
}
export default Form;

工具栏.jsx

import React from "react";
import ToolbarItem from "./ToolbarItem";
const Toolbar = () => {
const _defaultItems = () => {
return [
{
key: "Header",
name: "Header Text",
icon: "fas fa-heading",
static: true,
content: "Place holder text"
},
{
key: "Label",
name: "Label",
static: true,
icon: "fas fa-font",
content: "Place holder text"
},
{
key: "Paragraph",
name: "Paragraph",
static: true,
icon: "fas fa-paragraph",
content: "Place holder text"
},
{
key: "LineBreak",
name: "Line break",
static: true,
icon: "fas fa-arrows-alt-h"
},
{
key: "Dropdown",
canHaveAnswer: true,
name: "Dropdown",
icon: "far fa-caret-square-down",
label: "Place holder label",
field_name: "dropdown_",
options: []
},
{
key: "Tags",
canHaveAnswer: true,
name: "Tags",
icon: "fas fa-tags",
label: "Place holder label",
field_name: "tags_",
options: []
},
{
key: "Checkboxes",
canHaveAnswer: true,
name: "Checkboxes",
icon: "far fa-check-square",
label: "Place holder label",
field_name: "checkboxes_",
options: []
},
{
key: "RadioButtons",
canHaveAnswer: true,
name: "Multiple choices",
icon: "far fa-dot-circle",
label: "Place holder label",
field_name: "radiobuttons_",
options: []
},
{
key: "TextInput",
canHaveAnswer: true,
name: "Text input",
label: "Place holder label",
icon: "fas fa-font",
field_name: "text_input_"
},
{
key: "NumberInput",
canHaveAnswer: true,
name: "Number input",
label: "Place holder label",
icon: "fas fa-plus",
field_name: "number_input_"
},
{
key: "TextArea",
canHaveAnswer: true,
name: "Multi line input",
label: "Place holder label",
icon: "fas fa-text-height",
field_name: "text_area_"
},
{
key: "TwoColumnRow",
canHaveAnswer: false,
name: "Two columns row",
label: "",
icon: "fas fa-columns",
field_name: "two_col_row_"
},
{
key: "ThreeColumnRow",
canHaveAnswer: false,
name: "Three columns row",
label: "",
icon: "fas fa-columns",
field_name: "three_col_row_"
},
{
key: "FourColumnRow",
canHaveAnswer: false,
name: "Four columns row",
label: "",
icon: "fas fa-columns",
field_name: "four_col_row_"
},
{
key: "Image",
name: "Image",
label: "",
icon: "far fa-image",
field_name: "image_",
src: ""
},
{
key: "Rating",
canHaveAnswer: true,
name: "Rating",
label: "Place holder label",
icon: "fas fa-star",
field_name: "rating_"
},
{
key: "DatePicker",
canDefaultToday: true,
canReadOnly: true,
dateFormat: "MM/dd/yyyy",
timeFormat: "hh:mm aa",
showTimeSelect: false,
showTimeSelectOnly: false,
showTimeInput: false,
name: "Date",
icon: "far fa-calendar-alt",
label: "Place holder label",
field_name: "date_picker_"
},
{
key: "Signature",
canReadOnly: true,
name: "Signature",
icon: "fas fa-pen-square",
label: "Signature",
field_name: "signature_"
},
{
key: "HyperLink",
name: "Website",
icon: "fas fa-link",
static: true,
content: "Place holder website link",
href: "http://www.example.com"
},
{
key: "Download",
name: "File attachment",
icon: "fas fa-file",
static: true,
content: "Place holder file name",
field_name: "download_",
file_path: "",
_href: ""
},
{
key: "Range",
name: "Range",
icon: "fas fa-sliders-h",
label: "Place holder label",
field_name: "range_",
step: 1,
default_value: 3,
min_value: 1,
max_value: 5,
min_label: "Easy",
max_label: "Difficult"
},
{
key: "Camera",
name: "Camera",
icon: "fas fa-camera",
label: "Place holder label",
field_name: "camera_"
},
{
key: "FileUpload",
name: "File upload",
icon: "fas fa-file",
label: "Place holder label",
field_name: "file_upload_"
}
];
};
return (
<div className="react-form-builder-toolbar">
<h4>Toolbox</h4>
<ul>
{_defaultItems().map((item, index) => {
return <ToolbarItem data={item} key={index} />;
})}
</ul>
</div>
);
};
export default Toolbar;

ToolbarItem.jsx

import React from "react";
import { useDrag } from "react-dnd";
import { ItemTypes } from "./ItemTypes";
function ToolbarItem(props) {
const data = props.data;
const [{ isDragging }, drag, dragPreview] = useDrag(() => ({
type: ItemTypes.CARD,
collect: (monitor) => ({
isDragging: monitor.isDragging()
}),
item: props.data
}));
return (
<li ref={drag} style={{ opacity: isDragging ? 0.5 : 1 }}>
<i className={data.icon}></i>
{data.name}
</li>
);
}
export default ToolbarItem;

我也尝试过将状态存储在redux中,并且仍然保持相同的行为。为了简单起见,我在Sandbox示例中将状态保留在父组件中。

Example.js文件中,尝试用此setItems((items)=>[...items, item]);替换

我认为这将解决问题。请在此处查看https://codesandbox.io/s/reactjs-dnd-example-forked-1lu5i9?file=/src/Form.jsx

最新更新