React-Draft-Wysiwyg 文本框的 React 动态列表在删除后未正确更新
React dynamic list of React-Draft-Wysiwyg text boxes not updating correctly after remove
Codesandbox link: https://codesandbox.io/s/tender-meadow-un6ny7?file=/src/index.js
我正在创建一个基本应用程序,您可以在其中通过 react-draft-wysiwyg 库动态添加文本框。
return (
<div className="editor">
<Editor
//Update and show text box content
editorState={editorState}
onEditorStateChange={(editorState) => {
let html = stateToHTML(editorState.getCurrentContent());
console.log(html);
setHtml(html);
props.setContent(editorId, html, editorState);
setEditorState(editorState);
}}
//Display toolbar on top
toolbar={{
inline: { inDropdown: true },
list: { inDropdown: true },
textAlign: { inDropdown: true },
link: { inDropdown: true },
history: { inDropdown: true },
}}
/>
</div>
);
};
文本框通过 React 状态挂钩进行存储和更新。一个控制每个文本框的实际呈现状态 (editorState),另一个存储每个文本框内容的原始 html (html)。状态挂钩已经定义了添加、删除和编辑行为。
const EditorContent = (props) => {
const [editorState, setEditorState] = useState(props.content);
const [html, setHtml] = useState("");
useEffect(() => {
console.log("loaded number " + props.id);
});
function App() {
//Declaration of editorList array and setList setter
const [editorList, setEditorList] = useState([
{ id: 0, html: "", content: EditorState.createEmpty() },
]);
const [numberofEditors, setNumberOfEditors] = useState(0);
//Lets you view editorList content in inspect tab
console.log(editorList);
//Used to find specific instance, not used in current code
//Refer to video, forgot what it's used for
const handleServiceChange = (e, index) => {
const { name, value } = e.target;
console.log(name, value);
const list = [...editorList];
list[index][name] = value;
//setEditorList(list);
};
//Handles remove function
const handleEditorRemove = (id) => {
console.log("Remove id " + id);
// remove editor with designated id
let list = editorList.filter((editor) => {
return editor.id !== id;
});
console.log("Updated List: " + list);
setEditorList(list);
};
const handleEditorAdd = (id) => {
console.log(id);
setEditorList([
...editorList,
{ id: id, html: "", content: EditorState.createEmpty() },
]);
setNumberOfEditors(numberofEditors + 1);
};
const setEditorContent = (id, html, editorState) => {
console.log(id, html);
// deep copy array
let editorsCopy = [];
for (let editor of editorList) {
editorsCopy.push(editor);
}
const index = editorsCopy.findIndex((editor) => {
return editor.id === id;
});
editorsCopy[index].html = html;
editorsCopy[index].content = editorState;
setEditorList(editorsCopy);
};
每个文本框也呈现有两个按钮,一个用于添加另一个框,另一个用于删除该特定组件。
return (
<form className="App" autoComplete="off">
<div className="form-field">
<label htmlFor="editor">Editor(s)</label>
{editorList.map((editor, index) => (
<div key={index} className="services">
<div className="first-division">
<EditorContent id={editor.id} setContent={setEditorContent} />
{editorList.length - 1 === index && editorList.length < 4 && (
<button
type="button"
onClick={() => {
handleEditorAdd(numberofEditors + 1);
}}
className="add-btn"
>
<span>Add an Editor</span>
</button>
)}
</div>
<div className="second-division">
{editorList.length !== 1 && (
<button
type="button"
onClick={() => {
handleEditorRemove(editor.id);
}}
className="remove-btn"
>
<span>Remove</span>
</button>
)}
</div>
</div>
))}
</div>
<div className="output">
<h2>Output</h2>
{editorList &&
editorList.map((editor, index) => (
<ul key={index}>{editor.service && <li>{editor.content}</li>}</ul>
))}
</div>
</form>
);
}
添加新文本框和更新存储的 html 效果很好。但是,当我尝试删除特定文本框时,无论我使用哪个删除按钮 select,最后一行总是被删除。我尝试为每个文本框添加 id 键并进行拼接,但似乎没有任何东西可以正确呈现更改,尽管 HTML 数组显示了正确的文本。
我是否错误地更新了状态?或者只是渲染不正确?如有任何意见,我们将不胜感激。
我在你的代码中看到的唯一错误是你正在使用
key={index}
whilie渲染列表项,并根据官方文档
选择键的最佳方法是使用一个字符串来唯一标识列表项 siblings.Most 通常您会使用数据中的 ID 作为键
因此,您应该使用编辑器的 ID 而不是使用索引,这将使它正常工作,例如
{editorList.map((editor, index) => (
<div key={editor.id} className="services">
<div className="first-division">
<EditorContent id={editor.id} setContent={setEditorContent} />
{editorList.length - 1 === index && editorList.length < 4 && (
<button
type="button"
onClick={() => {
handleEditorAdd(numberofEditors + 1);
}}
className="add-btn"
>
<span>Add an Editor</span>
</button>
)}
</div>
<div className="second-division">
{editorList.length !== 1 && (
<button
type="button"
onClick={() => {
handleEditorRemove(editor.id);
}}
className="remove-btn"
>
<span>Remove</span>
</button>
)}
</div>
</div>
))}
Codesandbox link: https://codesandbox.io/s/tender-meadow-un6ny7?file=/src/index.js
我正在创建一个基本应用程序,您可以在其中通过 react-draft-wysiwyg 库动态添加文本框。
return (
<div className="editor">
<Editor
//Update and show text box content
editorState={editorState}
onEditorStateChange={(editorState) => {
let html = stateToHTML(editorState.getCurrentContent());
console.log(html);
setHtml(html);
props.setContent(editorId, html, editorState);
setEditorState(editorState);
}}
//Display toolbar on top
toolbar={{
inline: { inDropdown: true },
list: { inDropdown: true },
textAlign: { inDropdown: true },
link: { inDropdown: true },
history: { inDropdown: true },
}}
/>
</div>
);
};
文本框通过 React 状态挂钩进行存储和更新。一个控制每个文本框的实际呈现状态 (editorState),另一个存储每个文本框内容的原始 html (html)。状态挂钩已经定义了添加、删除和编辑行为。
const EditorContent = (props) => {
const [editorState, setEditorState] = useState(props.content);
const [html, setHtml] = useState("");
useEffect(() => {
console.log("loaded number " + props.id);
});
function App() {
//Declaration of editorList array and setList setter
const [editorList, setEditorList] = useState([
{ id: 0, html: "", content: EditorState.createEmpty() },
]);
const [numberofEditors, setNumberOfEditors] = useState(0);
//Lets you view editorList content in inspect tab
console.log(editorList);
//Used to find specific instance, not used in current code
//Refer to video, forgot what it's used for
const handleServiceChange = (e, index) => {
const { name, value } = e.target;
console.log(name, value);
const list = [...editorList];
list[index][name] = value;
//setEditorList(list);
};
//Handles remove function
const handleEditorRemove = (id) => {
console.log("Remove id " + id);
// remove editor with designated id
let list = editorList.filter((editor) => {
return editor.id !== id;
});
console.log("Updated List: " + list);
setEditorList(list);
};
const handleEditorAdd = (id) => {
console.log(id);
setEditorList([
...editorList,
{ id: id, html: "", content: EditorState.createEmpty() },
]);
setNumberOfEditors(numberofEditors + 1);
};
const setEditorContent = (id, html, editorState) => {
console.log(id, html);
// deep copy array
let editorsCopy = [];
for (let editor of editorList) {
editorsCopy.push(editor);
}
const index = editorsCopy.findIndex((editor) => {
return editor.id === id;
});
editorsCopy[index].html = html;
editorsCopy[index].content = editorState;
setEditorList(editorsCopy);
};
每个文本框也呈现有两个按钮,一个用于添加另一个框,另一个用于删除该特定组件。
return (
<form className="App" autoComplete="off">
<div className="form-field">
<label htmlFor="editor">Editor(s)</label>
{editorList.map((editor, index) => (
<div key={index} className="services">
<div className="first-division">
<EditorContent id={editor.id} setContent={setEditorContent} />
{editorList.length - 1 === index && editorList.length < 4 && (
<button
type="button"
onClick={() => {
handleEditorAdd(numberofEditors + 1);
}}
className="add-btn"
>
<span>Add an Editor</span>
</button>
)}
</div>
<div className="second-division">
{editorList.length !== 1 && (
<button
type="button"
onClick={() => {
handleEditorRemove(editor.id);
}}
className="remove-btn"
>
<span>Remove</span>
</button>
)}
</div>
</div>
))}
</div>
<div className="output">
<h2>Output</h2>
{editorList &&
editorList.map((editor, index) => (
<ul key={index}>{editor.service && <li>{editor.content}</li>}</ul>
))}
</div>
</form>
);
}
添加新文本框和更新存储的 html 效果很好。但是,当我尝试删除特定文本框时,无论我使用哪个删除按钮 select,最后一行总是被删除。我尝试为每个文本框添加 id 键并进行拼接,但似乎没有任何东西可以正确呈现更改,尽管 HTML 数组显示了正确的文本。
我是否错误地更新了状态?或者只是渲染不正确?如有任何意见,我们将不胜感激。
我在你的代码中看到的唯一错误是你正在使用
key={index}
whilie渲染列表项,并根据官方文档
选择键的最佳方法是使用一个字符串来唯一标识列表项 siblings.Most 通常您会使用数据中的 ID 作为键
因此,您应该使用编辑器的 ID 而不是使用索引,这将使它正常工作,例如
{editorList.map((editor, index) => (
<div key={editor.id} className="services">
<div className="first-division">
<EditorContent id={editor.id} setContent={setEditorContent} />
{editorList.length - 1 === index && editorList.length < 4 && (
<button
type="button"
onClick={() => {
handleEditorAdd(numberofEditors + 1);
}}
className="add-btn"
>
<span>Add an Editor</span>
</button>
)}
</div>
<div className="second-division">
{editorList.length !== 1 && (
<button
type="button"
onClick={() => {
handleEditorRemove(editor.id);
}}
className="remove-btn"
>
<span>Remove</span>
</button>
)}
</div>
</div>
))}