【问题标题】:How to set new value in two dimensional array with useState()如何使用 useState() 在二维数组中设置新值
【发布时间】:2021-09-23 14:34:01
【问题描述】:

here for a Codesandbox displaying my problem。尝试在textareas 中输入几个字,看看出了什么问题。

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

不使用 useState React 钩子(Codesandbox 的左侧),这一切都可以正常工作。我刚刚声明了一个变量 const content = [[]] 并将单个单词推送到数组中。但是,由于某种原因,在使用 useState (const [content, setContent] = useState([[]])) 时,数组的更新完全不同。

如何使 Codesandbox 示例中的(左)示例与 React useState 挂钩(Codesandbox 中的右示例)一起使用,我做错了什么?

【问题讨论】:

    标签: javascript arrays reactjs react-hooks


    【解决方案1】:

    所以我在不使用 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>
        );
    }
    

    【讨论】:

    • 我现在才得到更改来查看您的答案。这正是我想要的。为什么我不必将content 的状态复制到newContent 中?
    • 这是因为在您的WithoutUseState 代码中,因为您没有使用状态,所以每次组件呈现时您总是有content = [[]],但是在带有useState 的代码中,里面有您以前的状态值内容,如果您不重新初始化将不会产生类似的结果。
    猜你喜欢
    • 1970-01-01
    • 2020-02-14
    • 2012-10-22
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-08
    • 2017-12-07
    相关资源
    最近更新 更多