如何在for循环中多次更新状态?ReactJS



我正试图使用for循环来运行一个函数10次,它依赖于以前的状态来更新。我知道我不应该在循环中setState,因为状态更改是分批的,那么如果我想用单击处理程序运行函数10次,我的选项是什么?如果这很重要的话,我正在使用钩子(useState(。

以下是我的相关代码:

export default function Rolls(props) {
    const [roll, setRoll] = useState(null)
    const [tenPityCount, setTenPityCount] = useState(0)
    const [ninetyPityCount, setNinetyPityCount] = useState(0)

    // handler for single roll
    const handleSingleRoll = () => {
        // sets the main rolling RNG
        const rng = Math.floor(Math.random() * 1000) +1
        // pulls a random item from the data set for each star rating
        const randomFiveStar = Math.floor(Math.random() * fiveStarData.length) 
        const randomFourStar = Math.floor(Math.random() * fourStarData.length)
        const randomThreeStar = Math.floor(Math.random() * threeStarData.length)
        
        // check if ten pity count has hit
        if (tenPityCount === 9) {
            setRoll(fourStarData[randomFourStar].name)
            setTenPityCount(0)
            return;
        } 
        // check if 90 pity count has hit
        if (ninetyPityCount === 89) {
            setRoll(fiveStarData[randomFiveStar].name)
            setNinetyPityCount(0)
            return;
        } 
        // check if rng hit 5 star which is 0.6%
        if (rng <= 6) {
            setRoll(fiveStarData[randomFiveStar].name)
            setNinetyPityCount(0)
        // check if rng hit 4 star which is 5.1%
        } else if (rng <= 51) {
            setRoll(fourStarData[randomFourStar].name)
            setTenPityCount(0)
            // only increment for 90 pity counter b/c 10 pity resets upon hitting 4 star
            setNinetyPityCount(prevState => prevState +1)
        // anything else is a 3 star
        } else {
            setRoll(threeStarData[randomThreeStar].name)
            // pity counter increment for both
            setTenPityCount(prevState => prevState + 1)
            setNinetyPityCount(prevState => prevState +1)
        }
    }
    
    const handleTenRoll = () => {
        for (let i = 0; i < 10; i++) {
            handleSingleRoll()
        }
    }
    
    return (
        <>
        <div>
            <span>
                <button onClick={handleSingleRoll} className='btn btn-primary mr-2'>Wish x1</button>
                <button onClick={handleTenRoll} className='btn btn-primary mr-2'>Wish x10</button>
                <button className='btn btn-danger'>Reset</button>
            </span>
        </div>
        </>
    )
}

我的建议是使用代理函数:

const [roll, setRollState] = useState(null)
const [tenPityCount, setTenPityCountState] = useState(0)
const [ninetyPityCount, setNinetyPityCountState] = useState(0)
const newState = useRef({});
const consolidatedUpdates = useRef({setRollState, setTenPityCountState, setNinetyPityCountState})
function presetStateUpdate(name, state){
   newState.current[name] = state
}
function pushPresetState(){
   Object.entries(newState.current).forEach(([fnName, value]) => {
      const fn = consolidatedUpdates[fnName];
      if(typeof fn == 'function') fn(value);
   });
   newState.current = {};
}
const setRoll = v => presetStateUpdate('setRoll', v);
const setTenPityCount = v => presetStateUpdate('setTenPityCount', v);
const setNinetyPityCount = v => presetStateUpdate('setNinetyPityCount', v);

分别为:

const handleTenRoll = () => {
    for (let i = 0; i < 10; i++) {
        handleSingleRoll()
    }
    pushPresetState()
}

最新更新