React+TS开发Cookie类点击器:随机弹窗元素不显示问题求助
问题:随机弹窗元素无法显示
开发Cookie类点击器时,遇到随机弹窗元素完全不显示的问题,目标是实现类似Cookie Clicker中金饼干的功能:元素按随机间隔在屏幕随机位置出现,点击后触发相应操作。
相关代码
Caravan.tsx
interface CaravanProps{ x: number; y:number; } function randomNumberBetween(min: number, max: number): number { return Math.random() * (max - min) + min; } export let CaravanGen = () => { let caravanList: Array<JSX.Element> = new Array<JSX.Element>(); const[carList, setCarList] = useState(caravanList); useEffect(() => { let timer = randomNumberBetween(3000, 6000); let newCarList = carList; const interval = setInterval(() => { const x = randomNumberBetween(0, 1900); const y = randomNumberBetween(0, 1000); newCarList.push(<Caravan x={x} y={y}/>); setCarList(newCarList); console.log(x, y); }, timer); return () => { clearInterval(interval); }; }, []); return(<div className='caravan-gen'>{caravanList}</div>); } export function Caravan(props: CaravanProps) { return( <div style={{ position: 'absolute', left: props.x, top: props.y, width: "100px", height: "100px", borderRadius: "100%", backgroundColor: "black" }}> </div> ); }
index.css
.caravan-pop{ width: 100px; height: 100px; border-radius: 100%; background-color: black; z-index: 10; }
修复方案
核心问题与修复点
- 渲染对象错误:
CaravanGen返回的是初始空数组caravanList,而非状态变量carList,状态更新后视图不会同步刷新,需改为渲染{carList}。 - 数组引用未更新:直接赋值
let newCarList = carList是复用原数组引用,push修改后React无法检测到状态变化,必须创建新数组(如const newCarList = [...carList])。 - 定时器间隔固定:当前
timer仅初始化一次,后续弹窗都会用同一个间隔,不符合随机需求,改用递归setTimeout实现每次生成新的随机间隔。 - 父容器定位缺失:绝对定位的子元素需要父容器设置
position: relative,否则会相对于整个文档定位,容易超出可视区域。
修复后的CaravanGen组件
export let CaravanGen = () => { const [carList, setCarList] = useState<JSX.Element[]>([]); useEffect(() => { const generateCaravan = () => { const timer = randomNumberBetween(3000, 6000); const timeoutId = setTimeout(() => { // 计算位置时减去元素尺寸,确保完全显示在可视区内 const x = randomNumberBetween(0, window.innerWidth - 100); const y = randomNumberBetween(0, window.innerHeight - 100); // 用函数式更新创建新数组,避免依赖外部状态 setCarList(prev => [...prev, <Caravan key={Date.now() + Math.random()} x={x} y={y}/>]); generateCaravan(); // 递归调用,实现下一次随机间隔 }, timer); return timeoutId; }; const timeoutId = generateCaravan(); return () => clearTimeout(timeoutId); }, []); // 父容器设置相对定位和最小高度,确保弹窗定位正常 return(<div className='caravan-gen' style={{position: 'relative', minHeight: '100vh'}}>{carList}</div>); }
补充说明
- 给每个
Caravan元素添加唯一key,避免React列表渲染警告。 - 计算x/y坐标时减去元素宽高,防止弹窗超出屏幕可视范围。
- 父容器设置
minHeight: '100vh',确保占满整个视口高度,避免弹窗位置异常。
内容的提问来源于stack exchange,提问作者Okneas
相关产品推荐
相关产品推荐

