当我使用React钩子更改数组中对象的属性时,组件不会重新呈现。
我咨询了我的首席技术人员,他解释说,React搜索“宽度”而不是“深度”,这意味着React可以看到对象,但是看不到对象属性的更改。
const [array, setArray] = useState([
{'id': 0, text: '0'},
{'id': 1, text: '1'},
{'id': 2, text: '2'}
]);
我希望此组件在状态更改时能够重新呈现,但是行为的表现就好像对象数组完全没有更改。
如果我将数组的副本创建为newArray并更改newArray [2] .text ='3'和setArray(newArray),则react认为该数组未更改。因此,该组件不会重新加载。
作为解决方法,我使用
const [trigger, setTrigger] = useState(false);
setTrigger(!trigger);
强制重新加载。但是,这是一种重新加载组件的方法,我想要一种更React的方式。
谢谢前进!
答案 0 :(得分:1)
我认为问题在于您如何复制阵列。 js中的数组是reference type
,所以您不能仅仅这样做:
const arr = [1,2,4]
const copy = arr
因为您只是在更改指针而不是引用本身。试试这个:
const copy = [...arr]
现在,您将使用每个spread
个元素中的arr
个来创建一个新数组。要使用useState
const Comp = () =>{
const [arr, setArr] = useState([1,2,3,4])
return <button onClick={() => setArr([...arr, 5])}>Change</button>
}
答案 1 :(得分:1)
您的领先技术所说的“深呼吸”是正确的。
React仅监视“参考”更改。更改对象的属性时,引用是相同的。
想想想起来,a.value
仍然可以更改,即使它被声明为常量。
const a = {value: 'abc'}
a.value = 'xxx'
console.log(a.value) // prints 'xxx'
但是你不能做
const a = {value: 'abc'}
a = {something: 'bad'}
? not allowed.
这同样适用于对象数组(或普通的旧数组)。
这是一种引用类型,因此更改数组元素的属性不会更改newArray
的引用。
newArray[2].text = '3' and setArray(newArray)
newArray
仍指向相同的地址空间。
因此,当您使用扩展语法或Array.from
创建一个新数组时,将创建一个新引用(副本),并设置一个新值,最后设置状态。
const [array, setArray] = useState([
{'id': 0, text: '0'},
{'id': 1, text: '1'},
{'id': 2, text: '2'}
]);
// ... somewhere else.
const copy = [...array, {'id': 2, ]
// or -> const copy = Array.from(array)
copy[2].text = '3'
setArray(copy)
上面的代码创建了一个copy
状态的新array
。将该副本设置为具有更新的值将触发重新渲染。 (但是请注意,它会创建一个“浅副本”,而不是“深副本”)
由于数据结构复杂,因此不妨使用ImmerJS,它使您可以像编写当前代码一样更改引用。