如何使用useState()在二维数组中设置新值



查看这里显示我的问题的代码盒。试着在两个textareas中输入一些单词,看看哪里出错了。

我是React新手。我试图动态创建一个基于用户输入的svg element。我正在拆分单个单词,计算这些单词的宽度,并将它们推入内容数组。

不使用useState React钩子(Codesandbox的左侧),这一切都工作得很好。我刚刚声明了一个变量const content = [[]],并将单个单词推入数组。但是,由于某些原因,当使用useState (const [content, setContent] = useState([[]]))时,数组的更新完全不同。

我如何使我的(左)例子从Codesandbox的例子工作与React useState钩子(右例子从Codesandbox),我做错了什么?

所以我修复了你的代码,你有它的工作方式,而不使用useState钩子的content。我创建了两个新的状态,并使用了useEffect,这是必要的。

当状态改变组件重新呈现,所以你需要小心的状态改变,在你的情况下,你不需要复制content的状态到newContent,相反,你需要重新初始化它,就像你在顶部初始化状态时所做的一样。

同样,你也需要使用useEffect钩子,在那里你可以运行一部分依赖于某些变量的代码,在你的情况下,它是dummyText, wordsWithComputedWidth, spaceWidth在不同的位置。

import { useState, useEffect } from "react";
export default function WithUseState() {
const [dummyText, setDummyText] = useState("");
const [wordsWithComputedWidth, setWordsWithComputedWidth] = useState(1);
const [spaceWidth, setSpaceWidth] = useState(0);
const [content, setContent] = useState([[]]);
function calculateWordWidths(v) {
const words = v.split(/s+/);
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
let text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.style =
"font: 10pt LiberationSans, Helvetica, Arial, sans-serif; white-space: pre;";
svg.appendChild(text);
document.body.appendChild(svg);
const wordsWithComputedWidth = words.map((word) => {
text.textContent = word;
return { word, width: text.getComputedTextLength() };
});
text.textContent = "u00A0"; // Unicode space
const spaceWidth = text.getComputedTextLength();
document.body.removeChild(svg);
return { wordsWithComputedWidth, spaceWidth };
}
useEffect(() => {
let { wordsWithComputedWidth, spaceWidth } = calculateWordWidths(dummyText);
setWordsWithComputedWidth(wordsWithComputedWidth);
setSpaceWidth(spaceWidth);
}, [dummyText]);
useEffect(() => {
let xPos = 0;
let yPos = 16;
let page = 1;
let i = 0;
let len = wordsWithComputedWidth.length;
let newContent = [[]];
while (i < len) {
if (yPos > 25) {
newContent.push([]);
page++;
xPos = 0;
yPos = 16;
}
newContent[page - 1].push(
<text
x={xPos}
y={yPos}
key={i + xPos + yPos + wordsWithComputedWidth[i].word}
style={{
font: "10pt LiberationSans, Helvetica, Arial, sans-serif",
whiteSpace: "pre"
}}
>
{wordsWithComputedWidth[i].word}
</text>
);
xPos += wordsWithComputedWidth[i].width + spaceWidth;
if (xPos > 25) {
yPos += 16;
xPos = 0;
}
i++;
}
setContent(newContent);
}, [wordsWithComputedWidth, spaceWidth]);
function renderContentStructure() {
return content.map((page, pageIdx) => {
return (
<>
<span style={{ fontWeight: "bold" }}>Page: {pageIdx}</span>
<ol key={pageIdx}>
{page.map((fields, fieldIdx) => {
return <li key={fieldIdx}> {fields} </li>;
})}
</ol>
</>
);
});
}
return (
<div className="with-use-state">
<div>
Currently NOT working <strong>With</strong> useState
</div>
<div style={{ marginTop: "50px" }}>
<div className="content">
<div>Content</div>
<textarea
rows="6"
cols="24"
onChange={(e) => setDummyText(e.target.value)}
placeholder="type here..."
/>
</div>
<div className="preview">
<div>Preview</div>
<>
{content.map((page, idx) => (
<svg
viewBox="0 0 50 50"
xmlns="http://www.w3.org/2000/svg"
style={{
border: "1px solid #aaa",
width: "100px",
display: "block"
}}
key={idx}
>
{page}
</svg>
))}
</>
</div>
<div>{renderContentStructure()}</div>
</div>
</div>
);
}

最新更新