使用 map 生成元素时反应改变 useState 不渲染组件

React changing useState not rendering component when using map to generate elements

这是我的情况,我正在加载 SVG 文件并将其渲染到屏幕上。我想更改为 svg 文件的颜色。 (svg 文件包含 500 个对象)

一切正常,似乎状态已更改但组件未呈现。我认为这是因为我正在使用地图来生成元素 - 这是我的代码:

const Sim = () => {

    const [elements, setElements] = useState([]);

    const loadSVG = (e) => {
       ...
       ...
            newElements = newElements.map(x=> ({
                data: x,
                color: '#0a22a0'
            }))

            setElements(newElements)
        };
    }

    const rndColors = () => {

        elements.forEach(x=> {
            x.color = "#" + Math.floor(Math.random()*16777215).toString(16);
        })

        setElements(elements)
        console.log(elements)
        
    }

    return (
        <div>
            <Button style={{marginBottom: 10, maxHeight: 20}} size="small" variant="outlined" onClick={rndColors}>RND Colors</Button>
            <svg
                viewBox="0 0 2000 2000"
                version="1.1"
                x="0px"
                y="0px"
                style={{maxHeight:700}}
            >
            {elements.map((x,i) =>
                <SVGElement
                    data={x.data}
                    index={i}
                    color={x.color}
                />)
            }
            </svg>

        </div>
    )
}

我可以在日志中清楚地看到颜色发生了变化,但实际的 svg 颜色没有改变(只有在我更改代码中的内容后页面才会刷新 - 我可以看到新的颜色)

我怎样才能确保一旦我点击按钮,svg 的所有颜色都会改变?这里有些东西没有触发元素的渲染周期。我在这里缺少什么?

elements.forEach((x) => {
  x.color = "#" + Math.floor(Math.random() * 16777215).toString(16);
});

setElements(elements);

你正在改变上面的状态,你应该总是以 immutable 的方式更新状态。您可以将上面的代码重写为:

setElements(
  elements.map((x) => ({
    ...x,
    color: "#" + Math.floor(Math.random() * 16777215).toString(16),
  }))
);