React中useState动态创建二维数组的更新异常问题排查
Array.fill()初始化矩阵会导致整列同步修改? 这个问题的核心在于**Array.fill()处理引用类型时的行为特性**,咱们一步步拆解清楚:
1. 错误初始化方式的问题所在
当你用这段代码创建矩阵时:
const n = 4; const [matrix, setMatrix] = useState(Array(n).fill(Array(n).fill(null)));
你其实只创建了一个内层数组,然后把这个数组的引用重复填充到了外层数组的每一个位置。也就是说,matrix[0]、matrix[1]、matrix[2]... 全都是指向同一个数组对象的指针。
这就导致了:当你在handleChange里修改copy[row][column]时,你本质上是在修改那个唯一的内层数组,所以矩阵里所有行的第column个元素都会同步变化——因为它们本来就是同一个东西。
哪怕你在handleChange里做了let copy = [...matrix];,这也只是复制了外层数组的引用,内层的那些数组还是原来的同一个引用,所以修改行为依然会影响所有行。
2. 为什么Array.from的方式能正常工作?
再看这段正确的初始化代码:
const [matrix, setMatrix] = useState( Array.from({ length: 3 }, v => Array.from({ length: 3 }, v => null)) );
Array.from的第二个参数是一个映射函数,它会为外层数组的每一个元素(也就是每一行)都执行一次这个函数。每次执行v => Array.from(...)时,都会创建一个全新的内层数组——这意味着每一行都是独立的引用,彼此之间没有关联。
所以当你修改某一行的某个元素时,只会影响这一行对应的数组,其他行完全不受影响,自然就能正常工作了。
额外补充:另一种正确的初始化方式
除了Array.from,你也可以用Array(n).map()来实现同样的效果,因为map会为每个元素执行回调并返回新值:
const [matrix, setMatrix] = useState(Array(n).map(() => Array(n).fill(null)));
这里的() => Array(n).fill(null)会为外层数组的每个位置生成一个新的内层数组,同样能避免引用共享的问题。
内容的提问来源于stack exchange,提问作者Ronald Groot Jebbink

