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

React开发数独应用时数组state用扩展运算符未追加数据如何解决

问题原因
  • React的setState是异步批量更新的,你在createSudokValues的for循环中连续调用setSudoku时,函数作用域内捕获的sudoku变量永远是初始的空数组,不会随之前的setSudoku调用实时更新,导致生成第2~9行时,unusedDigitInRowAndColumn判断列重复的逻辑拿到的永远是空数组,甚至会出现可选数字为空返回undefined的异常,提前终止执行。
  • 你在循环中逐行调用setSudoku的逻辑没必要,完全可以先生成完整的数独数组,再一次性赋值给state,避免异步更新带来的闭包问题。
  • 内层冗余的while循环可以直接删除,外层的列循环已经保证了每行生成9个格子。
修正方案

把逐行更新state的逻辑改为先在本地变量生成完整数独数组,再一次性调用setSudoku赋值,同时增加了可用数字为空的兜底逻辑、给监听sudoku的useEffect补充了依赖项避免不必要的执行:

import React, { useEffect, useState } from 'react';
import '../App.css';
import { SquareType } from '../interfaces/customInterfaces';
import Square from './Square';

function App() {
    const [sudoku, setSudoku] = useState<SquareType[]>([]);
    const possibleOptionsForDigit = [1, 2, 3, 4, 5, 6, 7, 8, 9];

    function generateRandomArrayIndex(unusedDigits: Array<number> ) {
        return Math.floor(Math.random() * unusedDigits.length);
    }

    function unusedDigitInRowAndColumn( fullSudoku: Array<SquareType>, currentRow: Array<SquareType>, columnIndex: number ) {
        const digitsExistingInRow = currentRow.map(square => square.digit);
        const unusedDigitsInRow = possibleOptionsForDigit.filter(digit => !digitsExistingInRow.includes(digit));
    
        const digitsExistingInColumn = fullSudoku.filter(square => square.index === columnIndex).map(square => square.digit);
        const unusedDigitsInColumn = possibleOptionsForDigit.filter(digit => !digitsExistingInColumn.includes(digit));
    
        const unusedDigits = unusedDigitsInRow.filter(digit => unusedDigitsInColumn.includes(digit)); 
        // 兜底避免生成死局时无可用数字报错
        if (unusedDigits.length === 0) return possibleOptionsForDigit[generateRandomArrayIndex(possibleOptionsForDigit)]
        return unusedDigits[generateRandomArrayIndex(unusedDigits)];
    }

    function createSudokValues() {
        // 本地变量存储完整数独,规避state异步更新问题
        const fullSudoku: SquareType[] = [];

        for ( let y = 1; y <= 9; y++ ) {
            const row: SquareType[] = [];
            for ( let columnIndex = 1; columnIndex <= 9; columnIndex++ ) {
                const generatedUnusedDigit = unusedDigitInRowAndColumn(fullSudoku, row, columnIndex);
                row.push(
                    {
                        digit: generatedUnusedDigit,
                        index: columnIndex,
                        shown: true
                    }
                );
            }
            fullSudoku.push(...row);
        }
        // 生成完成后一次性更新state
        setSudoku(fullSudoku);
    }

    useEffect(() => {
        console.log('sudoku ', sudoku)
    }, [sudoku]);

    useEffect(() => {
        createSudokValues();
    }, []);

    return (
        <div className="App">
            <div className="pageContainer">
                <p>Sudoku</p>
                <div className="sudokuContainer">
                    {
                        sudoku.map((square, idx) =>
                        <Square key={idx} {...square}></Square>
                        )
                    }
                </div>
            </div>
        </div>
    );
}

export default App;

内容的提问来源于stack exchange,提问作者rumon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:24:06