Estoy tratando de actualizar una matriz de valores de 20x20, cada ranura está vinculada a un div, una vez que se hace clic en un div, su color de fondo debería cambiar.
¿Cuál es la mejor manera de hacer esto, sin tener que configurar toda la matriz?
Además, ¿por qué algunos métodos establecidos no funcionan, ya que la mayoría de estos se usan en ejemplos a través de 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;
Un saludo y gracias.
Debe actualizar utilizando la función setMatrix
y debe pasar una nueva matriz a esa función (cuando use ganchos, siempre debe ser una nueva referencia/objeto) :
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 }
EDITAR:
Además, Array(n).fill
pondrá la misma referencia en cada lugar de la matriz, por lo que cambiar un valor actualizará todo (porque todos tienen el mismo valor/referencia) .
cambiar la línea
useState(Array(n).fill(Array(n).fill({ color: "red" })))
a:
useState( Array.from({ length: 20 }, () => Array.from({length: 20}, () => ({ color: 'red' })) ) )
Respuesta hecha con la ayuda de estos comentarios (Chris G y RCC):
Estás cambiando de estado en el lugar; React no actualizará el componente a menos que sea una matriz de matriz completamente nueva. La cuarta variante tampoco debería tener efecto. El quinto cambia la matriz de una matriz a un objeto, esos no tienen una función de mapa ya que no son matrices.
Debe actualizar usando la función setMatrix y debe pasar una nueva matriz a esa función (cuando usa ganchos, siempre debe ser una nueva referencia/objeto)
Sí, el problema es cómo estás llenando la matriz. { color: "red" } crea un único objeto y todos los elementos de la matriz contienen/apuntan a ese único objeto. Cambiar la propiedad de color hará eso para todos los elementos.
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]); }