更新矩阵 useState 挂钩状态变量的特定值

Updating specific values of matrix useState hook state variable

我正在尝试更新一个 20x20 值的矩阵,每个插槽都绑定到一个 div,单击 div 后,它的背景颜色应该会改变。

在不必设置整个矩阵的情况下执行此操作的最佳方法是什么?

此外,为什么有些设置方法不起作用,因为其中大部分都通过 Internet 在示例中使用?

import { useState } from "react";

function App() {
  const n = 20;

  // define [20][20] array with default value on each slot as { color: "red" }
  const [matrix, setMatrix] = useState(Array(n).fill(Array(n).fill({ color: "red" })))

  let updateCell = (i, j) => {
    console.log(i, j); // Works perfectly, returns i and j of the matrix slot binded to the clicked cell.

    // const mat = matrix; mat[i][j].color = "blue";                  // Doesnt work
    // setMatrix((mat) => { mat[i][j].color = "blue"; return mat; }); // Doesnt work
    // matrix[i][j].color = "blue"; setMatrix(matrix);                // Doesnt work
    // matrix[i][j].color = "blue"; setMatrix([...matrix]);           // Changes ALL squares instead of the one clicked.
    // const mat = Object.assign({}, matrix); setMatrix(mat);         // TypeError: matrix.map is not a function
  }

  return (

    <div className="container">

      {/* Renders all squares fine! */}
      {matrix.map((i, ipos) => {
        console.log(matrix.length);

        return (
          <div key={ipos} className="d-flex flex-row wrap">

            {i.map((j, jpos) => {
              console.log(i.length);
              return (

                <div
                  style={{ backgroundColor: matrix[ipos][jpos].color, minWidth: "5%", minHeight: "50px", textAlign: "center", color: "white" }}
                  key={ipos + ", " + jpos}
                  onClick={() => { updateCell(ipos, jpos) }}
                >
                  {ipos + ", " + jpos}
                </div>

              )
            })}

          </div>
        )

      })}

    </div>
  )
}

export default App;

此致,谢谢。

您需要使用 setMatrix 函数进行更新,并且需要向该函数传递一个新数组 (使用挂钩时,始终需要一个新数组 reference/object) :

const updateCell = (i, j) => {
  let newMatrix = matrix.slice(); // just to create a copy of the matrix
  newMatrix[i][j].color = "blue";
  setMatrix( newMatrix ); // this call will trigger a new draw
}

编辑:
此外,Array(n).fill 将在矩阵的每个位置放置相同的引用,因此更改一个值将更新所有 (因为它们都是相同的值/引用).

换行

useState(Array(n).fill(Array(n).fill({ color: "red" })))

至:

useState( Array.from({ length: 20 }, () => Array.from({length: 20}, () => ({ color: 'red' })) ) )

借助这些评论(Chris G 和 RCC)做出的回答:

You're changing state in place; React won't update the component unless it's a completely new matrix array. The fourth variant should have no effect either. The fifth changes matrix from an array to an object, those don't have a map function since they aren't arrays.

You need to update useing the setMatrix function, and need to pass a new Array to that function (when using hooks, always need to be a new reference/object)

Yeah, the problem is how you're filling the array. { color: "red" } creates a single object, and all array elements contain/point to that single object. Changing the color property will do that for all elements.

  useEffect(() => {
    const n = 20;

    for (let i = 0; i < n; i++) {
      matrix[i] = [];
      for (let j = 0; j < n; j++) {
        matrix[i][j] = { color: "red", coords: [i, j] }
      }
    }

    setMatrix([...matrix]);

  }, [])

  let updateCell = (i, j) => {
    console.log(i, j);
    matrix[i][j].color = "blue";
    setMatrix([...matrix]);
  }