You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止部分React组件在其他组件状态变更时重渲染

问题解决:React中保持圆形初始位置不随重渲染改变

问题描述

需要渲染若干个随机定位的圆形,每个圆形带数值参数,点击后数值累加到左上角总分,同时圆形消失。当前功能正常,但点击时其他圆形会重新渲染并生成新随机位置,需让每个圆形初始位置仅生成一次。

问题根源

每次调用setCount更新总分时,组件会触发重新渲染,renderCircles函数会被再次执行,重新生成所有圆形的随机位置;同时ctr是普通变量,每次渲染都会重置,导致DOM id重复;直接操作DOM修改可见性的方式也不符合React状态驱动的设计理念。

解决方案

用React状态存储所有圆形的初始数据(包括位置、颜色、数值和显示状态),渲染时直接基于状态生成圆形,点击时通过更新状态来修改总分和对应圆形的显示状态:

修改后的完整代码

import { useState, useEffect } from "react";
import "./App.css";

function App() {
  const [count, setCount] = useState(0);
  const [circles, setCircles] = useState([]);

  // 生成随机数工具函数
  function getRandom(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min) + min);
  }

  // 初始化圆形数据,仅在组件挂载时执行一次
  useEffect(() => {
    const colorKeys = Object.keys(Color);
    const initialCircles = Array.from({ length: 15 }, () => ({
      id: Math.random().toString(36).slice(2),
      xPos: getRandom(3, 53),
      yPos: getRandom(3, 40),
      color: colorKeys[Math.floor(Math.random() * colorKeys.length)],
      value: getRandom(1, 100),
      isVisible: true
    }));
    setCircles(initialCircles);
  }, []);

  // 处理圆形点击事件
  const handleCircleClick = (circle) => {
    setCount(prev => prev + circle.value);
    setCircles(prev => prev.map(c => 
      c.id === circle.id ? {...c, isVisible: false} : c
    ));
  };

  return (
    <div className="App">
      <div className="App-game">
        {circles.filter(c => c.isVisible).map(circle => (
          <div key={circle.id}>
            <svg
              className="circle"
              onClick={() => handleCircleClick(circle)}
              style={{
                left: `calc(${circle.xPos}vw - 60px)`,
                top: `calc(${circle.yPos}vw - 60px)`,
                position: "absolute",
                visibility: circle.isVisible ? "visible" : "hidden"
              }}
            >
              <circle cx={30} cy={30} r={30} fill={circle.color} />
            </svg>
          </div>
        ))}
      </div>
      <div className='App-currency' style={{color: "black", fontSize: 80}}>
        {count}
      </div>
    </div>
  );
}

export default App;

class Color {
  static Green = new Color("green");
  static Blue = new Color("blue");
  static Yellow = new Color("yellow");
  static Red = new Color("red");
  static Pink = new Color("pink");
  static Orange = new Color("orange");

  constructor(name) {
    this.name = name;
  }
  toString() {
    return `Color.${this.name}`;
  }
}

关键改动说明

  • 使用useState存储circles数组,每个元素包含圆形的唯一id、位置、颜色、数值和显示状态
  • 用useEffect配合空依赖数组,仅在组件挂载时生成一次圆形初始数据,确保位置不会随重渲染改变
  • 点击事件不再直接操作DOM,而是通过更新circles状态中对应圆形的isVisible属性来控制显示/隐藏
  • 用每个圆形的唯一id作为React元素的key,避免渲染时的性能问题和标识错误
  • 更新总分时使用函数式更新(setCount(prev => prev + circle.value)),确保获取到最新的状态值

内容的提问来源于stack exchange,提问作者Ernest P W

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 03:20:24