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

React父组件更新multiplier时如何阻止StarAnimation不必要重渲染?

问题描述

我开发了一个带有星星动画、火箭和可更新multiplier的Crash赌博组件。每次调用startCrash更新multiplier状态时,明明和这个状态无关的StarAnimation子组件也会跟着重渲染。以下是相关代码:

父组件变量定义

const starSpeed = {
    'slow': 1,
    'medium': 0.7,
    'fast': 0.2,
}
const {money, setMoney} = useContext(MoneyContext);
const [multiplier, setMultiplier] = useState(1.00);
const [starHeightMultiplier, setStarHeightMutliplier] = useState(3)
const [starAnimationDuration, setStarAnimationDuration] = useState(starSpeed.slow)
const [rocketMargin, setRocketMargin] = useState(60)

更新multiplier的函数

function startCrash() {
    let timeOut = 500;
    const crashEnd = Math.floor(Math.random() * (1000 - 1 + 1)) + 1;
    timeOut = 300
    for (let i = 101; i < crashEnd; i++) {
        setTimeout(() => {
            setMultiplier(i/100)
        }, timeOut)
        timeOut += 300;
    }
}

父组件返回内容

<>
    <div className={styles.crashGambleWrapper}>
        <BetMenu money={money} startCrash={startCrash}></BetMenu>

        <h2 className={styles.betMultiplierNum}>{multiplier.toFixed(2)}x</h2>
        <div className={styles.rocketGameWrapper}>
            <div className={styles.rocketWrapper}>
                <h1>CRASH GAMBLE</h1>
                
                <div className={styles.rocketDiv}>
                    <StarAnimation starAnimationDuration={starAnimationDuration} starHeightMultiplier={starHeightMultiplier}></StarAnimation>
                    <div className={styles.rocket} style={{marginTop: `${rocketMargin}vh`, animationDuration: '1s'}}>
                        <img src={rocket}></img>
                    </div>
                </div>
            </div>
        </div>
    </div>
</>

StarAnimation子组件代码

<>
    {[...Array(40).keys()].map(() => {
        let x = Math.floor(Math.random() * window.innerWidth*0.73)
        let h = Math.random() * starHeightMultiplier;
        let duration = Math.random() * 0.9 + starAnimationDuration;
        return <i style={{
            left: `${x}px`,
            width: `1px`,
            top: '1px',
            height: `${h}px`,
            animationDuration: `${duration}s`
        }}></i>
    })}
</>
解决方法

要阻止StarAnimation的不必要重渲染,核心是让它只在依赖的props变化时才更新,具体操作如下:

  • 用React.memo包裹StarAnimation组件
    React.memo会对组件传入的props做浅比较,只有当props确实变化时,才会触发组件重渲染。修改后的StarAnimation组件如下:
import { memo } from 'react';

const StarAnimation = memo(({ starAnimationDuration, starHeightMultiplier }) => {
    return (
        <>
            {[...Array(40).keys()].map(() => {
                let x = Math.floor(Math.random() * window.innerWidth*0.73)
                let h = Math.random() * starHeightMultiplier;
                let duration = Math.random() * 0.9 + starAnimationDuration;
                return <i style={{
                    left: `${x}px`,
                    width: `1px`,
                    top: '1px',
                    height: `${h}px`,
                    animationDuration: `${duration}s`
                }}></i>
            })}
        </>
    )
})

export default StarAnimation;
  • 可选优化:避免渲染时生成新数组
    当前组件里[...Array(40).keys()]每次渲染都会生成新数组,虽然不会触发React.memo的重渲染,但可以提前定义这个数组来减少不必要的计算:
// 放在组件外部,避免每次渲染生成新数组
const STAR_INDEXES = [...Array(40).keys()];

const StarAnimation = memo(({ starAnimationDuration, starHeightMultiplier }) => {
    return (
        <>
            {STAR_INDEXES.map(() => {
                // 原有逻辑不变
            })}
        </>
    )
})

这样处理后,父组件更新multiplier状态时,StarAnimation的props没有变化,就不会触发无意义的重渲染了。

内容的提问来源于stack exchange,提问作者Иван Йорданов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:40:04