数组的反应状态未使用扩展运算符附加

React state for array is not appended using spread operator

我正在使用 React.js 创建数独应用程序。

我遇到了一个问题,即仅在 createSudokValues() 的第一个内循环(仅创建数独的第一行)之后才将值写入状态 sudoku。外循环应该生成其余的行(按 setSudoku(prevSquares => [ ...prevSquares, ...row]);)。

我错过了什么?谢谢!

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

function App() {
    let row: Array<SquareType> = [];
    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( sudoku: Array<SquareType>, row: Array<SquareType>, columnIndex: number ) {
        let digitsExistingInRow: Array<number> = [];
        let digitsExistingInColumn: Array<number> = [];
        let unusedDigitsInRow: Array<number> = [];
        let unusedDigitsInColumn: Array<number> = [];
        let unusedDigits: Array<number>;
        let randomDigitFromUnused: number;
        
        digitsExistingInRow = row.map(square => square.digit);
        unusedDigitsInRow = possibleOptionsForDigit.filter(digit => !digitsExistingInRow.includes(digit));
    
        digitsExistingInColumn = sudoku.filter(square => square.index === columnIndex).map(square => square.digit);
        unusedDigitsInColumn = possibleOptionsForDigit.filter(digit => !digitsExistingInColumn.includes(digit));
    
        unusedDigits = unusedDigitsInRow.filter(digit => unusedDigitsInColumn.includes(digit)); 
        randomDigitFromUnused = unusedDigits[generateRandomArrayIndex(unusedDigits)];
    
        return randomDigitFromUnused;
    }

    function createSudokValues() {
        let generatedUnusedDigit: number = 0;

        for ( let y = 1; y <= 9; y++ ) {
            for ( let columnIndex = 1; columnIndex <= 9; columnIndex++ ) {
                while (row.length <= 9) {
                    console.log('row ', row)
                    generatedUnusedDigit = unusedDigitInRowAndColumn(sudoku, row, columnIndex);
                    row.push(
                        {
                            digit: generatedUnusedDigit,
                            index: columnIndex,
                            shown: true
                        }
                    );
                    break;
                }
                
            }
            // end of inner loop

            // eslint-disable-next-line no-loop-func
            setSudoku(prevSquares => [ ...prevSquares, ...row]);
            row = [];
            // end of outer loop
        }
    }

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

    useEffect(() => {
        createSudokValues();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

    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;

这是打印到屏幕的第一行:

相当于第一行console.logged:

您应该在每次第一个循环运行时初始化行数组,而不是在函数内部使用变量。

所以这个函数:

function createSudokValues() {
    let generatedUnusedDigit: number = 0;

    for ( let y = 1; y <= 9; y++ ) {
        for ( let columnIndex = 1; columnIndex <= 9; columnIndex++ ) {
            while (row.length <= 9) {
                console.log('row ', row)
                generatedUnusedDigit = unusedDigitInRowAndColumn(sudoku, row, columnIndex);
                row.push(
                    {
                        digit: generatedUnusedDigit,
                        index: columnIndex,
                        shown: true
                    }
                );
                break;
            }
            
        }
        // end of inner loop

        // eslint-disable-next-line no-loop-func
        setSudoku(prevSquares => [ ...prevSquares, ...row]);
        row = [];
        // end of outer loop
    }
}

应该是:

function createSudokValues() {
    let generatedUnusedDigit = 0;

    let row: Array<SquareType> = [];
    let tempSudoku: Array<SquareType> = [];
    for (let y = 1; y <= 9; y++) {
      for (let columnIndex = 1; columnIndex <= 9; columnIndex++) {
        while (row.length <= 9) {
          console.log("row ", row);
          generatedUnusedDigit = unusedDigitInRowAndColumn(
            sudoku,
            row,
            columnIndex
          );
          row.push({
            digit: generatedUnusedDigit,
            index: columnIndex,
            shown: true
          });
          break;
        }
        tempSudoku.push(...row);
        row = [];
      }
    }
    setSudoku(tempSudoku);
  }

在循环内设置状态没有什么意义,因为出于性能原因,它会很糟糕,因为状态变量会触发无用的渲染。 并且您还应该删除 App 组件开头的 let row: Array<SquareType> = []; 初始化。