使用React Hooks更改数组中的对象属性不会引起重新渲染

时间:2019-07-31 18:03:12

标签: reactjs react-hooks

当我使用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的方式。

谢谢前进!

2 个答案:

答案 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,它使您可以像编写当前代码一样更改引用。