首页 > 解决方案 > 延迟的 redux 调度调用加速 UI 更新

问题描述

我正在尝试在 ReactJs、Redux 和 TS 中创建一个简单的块堆叠游戏。我想无限地从左到右移动堆栈中的顶行,直到按下 Space 或 Enter 键。首先,当 UI 加载时它工作正常,但在它开始加速 UI 更新后不久就会出现不一致的更新。像这样...

游戏预览

不一致的 UI 更新日志

我想在延迟 200 毫秒后每次渲染将位置更新 1 步。

我正在尝试这样做。

useEffect(() => {
    if (play) {
        setTimeout(() => {
            moveStackLine(JSON.parse(JSON.stringify(data)), direction);
        }, 200);
    }
});

moveStackLine 函数:

const moveStackLine = useCallback((_data: GameData, directionCopy: 'left' | 'right') => {
    console.log('_data1', _data);
    let _direction = directionCopy;
    const lastIndexData = _data[_data.length - 1];
    if (_direction === 'right' && lastIndexData[1] < gameWidth) {
        lastIndexData[0] += 1;
        lastIndexData[1] += 1;
    }
    if (_direction === 'left' && lastIndexData[0] > 0) {
        lastIndexData[0] -= 1;
        lastIndexData[1] -= 1;
    }

    if (lastIndexData[1] === gameWidth - 1) {
        _direction = 'left';
    } else if (lastIndexData[0] === 0) {
        _direction = 'right';
    }
    _data.splice(_data.length - 1, 1, lastIndexData);
    dispatch({ type: ACTIONS.CHANGE_ACTIVE_LINE_START_END_POS, payload: _data });

    if (_direction !== directionCopy) {
        dispatch({ type: ACTIONS.CHANGE_DIRECTION, payload: _direction });
    }
}, [dispatch, gameWidth]);

上面的函数改变了我的 rootState 中数据数组的开始和结束位置。

初始状态:

export const gameState: InitialGameState = {
  currentLine: 0,
  gameWidth: 16,
  gameHeight: 20,
  direction: 'right',
  play: true,
  data: [[2, 5], [0, 3], [4, 7]],
}

data 数组中的每个数组代表一条线以及该线的开始和结束位置。

我的渲染逻辑看起来像这样。

const renderLine = (startEndIndex: Array<number>) => {
    const columns = [];
    for (let j = 0; j < gameWidth; j++) {
        columns.push(
            <div className={cx(styles.ball, { [styles.active]: j >= startEndIndex[0] && j <= startEndIndex[1] })}></div>
        );
    }
    return columns;
}

const renderGame = () => {
    const lines = [];
    for (let i = 0; i < gameHeight; i++) {
        lines.push(
            <div id={i.toString()} className={styles.line}>
                {renderLine(data[i] || [-1, -1])}
            </div>
        )
    }
    return lines;
}

return (
    <>
        <div className={styles.gameContainer}>
            {renderGame()}
        </div>
    </>
)

标签: javascriptreactjstypescriptreduxreact-redux

解决方案


您在_data这里直接修改,我假设它也是您从 Redux 存储中检索到的对象。这意味着您要在 reducer 之外修改 redux 存储。

这样的事情会引起各种副作用。

您不仅在这样做,而且还在修改lastIndexData——这也是对 store 中对象的引用——在这里,你再次直接修改 store,而不是使用 reducer 更新它。

尝试

const moveStackLine = useCallback((data: GameData, directionCopy: 'left' | 'right') => {
// .concat will create a new array reference that you can (flatly) modify as you want
 const _data = data.concat()
// .concat will create a new array reference that you can (flatly) modify as you want
lastIndexData = _data[_data.length - 1].concat(); 

推荐阅读