React中更新二维数组matrix状态后useEffect未重执行的问题
问题:修改React二维数组状态后组件未触发更新
我通过useState初始化了二维数组状态matrix,并编写了修改该数组的置零算法。控制台打印显示matrix内容已经变化,但依赖matrix的useEffect并未触发组件更新,只有在VS Code中输入内容时才会触发重渲染。尝试调整setMatrix的使用方式,问题仍未解决。
原代码
import React, {MouseEvent, useEffect, useState} from 'react' const TwoDArray = () => { let twodarray:number[][] = [ [1,1,1,1], [1,0,1,1], [1,1,0,1], [0,0,0,1] ] const [matrix, setMatrix] = useState(twodarray) const setMatrixZeros = (matrix: number[][], ) => { let col0: number = 1, rows: number = matrix.length, cols = matrix[0].length for (let i: number = 0; i < rows; i++) { if (matrix[i][0] == 0) col0 = 0 for (let j: number = 1; j < cols; j++) if(matrix[i][j]==0) matrix[i][0] = matrix[0][j] = 0 } for (let i: number = rows - 1; i >= 0; i--) { for (let j: number = cols - 1; j >= 1; j--) { if (matrix[i][0] == 0 || matrix[0][j] == 0) matrix[i][j] = 0 } if(col0==0) matrix[i][0] = 0 } } const handleClick = (e: MouseEvent<HTMLButtonElement>) => { setMatrixZeros(matrix) } useEffect(() => { }, [matrix]); // Only re-run the effect if matrix changes console.log(matrix) return ( <div className="twodarray"> <div className="matrix"> { matrix.map((item, index) => { return <div key={index} className='box-container'> {item.map((i, idx) => <input type='text' key={idx} className='box' value={ i} readOnly/>)}</div> })} </div> <button onClick={handleClick }>Set Matrix Zeroes</button> </div> ) } export default TwoDArray
问题原因
React的状态更新依赖引用变化判断状态是否改变。你在setMatrixZeros函数中直接修改了matrix的原数组(数组是引用类型),虽然数组内容变了,但数组的引用地址没有改变,React会认为状态没有更新,因此不会触发组件重渲染,useEffect也不会执行。
解决方法
必须创建原数组的副本,在副本上修改内容,再通过setMatrix传入新的数组副本,触发状态更新。
修改后的代码示例
import React, {MouseEvent, useEffect, useState} from 'react' const TwoDArray = () => { let twodarray:number[][] = [ [1,1,1,1], [1,0,1,1], [1,1,0,1], [0,0,0,1] ] const [matrix, setMatrix] = useState(twodarray) // 修改函数,返回新的数组 const setMatrixZeros = (originalMatrix: number[][]): number[][] => { // 深拷贝原数组,避免修改原状态 const matrix = structuredClone(originalMatrix); let col0: number = 1, rows: number = matrix.length, cols = matrix[0].length for (let i: number = 0; i < rows; i++) { if (matrix[i][0] == 0) col0 = 0 for (let j: number = 1; j < cols; j++) if(matrix[i][j]==0) matrix[i][0] = matrix[0][j] = 0 } for (let i: number = rows - 1; i >= 0; i--) { for (let j: number = cols - 1; j >= 1; j--) { if (matrix[i][0] == 0 || matrix[0][j] == 0) matrix[i][j] = 0 } if(col0==0) matrix[i][0] = 0 } return matrix; } const handleClick = (e: MouseEvent<HTMLButtonElement>) => { // 生成新数组并设置状态 const newMatrix = setMatrixZeros(matrix); setMatrix(newMatrix); } useEffect(() => { console.log('matrix更新,触发useEffect'); }, [matrix]); console.log(matrix) return ( <div className="twodarray"> <div className="matrix"> { matrix.map((item, index) => { return <div key={index} className='box-container'> {item.map((i, idx) => <input type='text' key={idx} className='box' value={ i} readOnly/>)}</div> })} </div> <button onClick={handleClick }>Set Matrix Zeroes</button> </div> ) } export default TwoDArray
关键修改点
- 使用
structuredClone深拷贝原数组,确保不直接修改原状态。 - 修改
setMatrixZeros函数,让它返回处理后的新数组。 - 在
handleClick中调用函数得到新数组,再通过setMatrix更新状态,此时状态引用改变,React会触发组件重渲染和useEffect执行。
内容的提问来源于stack exchange,提问作者Azula Mongkhonvilay
相关产品推荐
相关产品推荐

