反转存储在 State 中的数组不会强制重新渲染 React 中的组件

IT技术 javascript reactjs react-hooks react-state
2021-05-04 11:16:03

这是一个较大组件的一部分,但我已在下面的可重现示例中对其进行了总结:

    import React, {useState} from 'react'

   
    function App() {
        const [data,setData] = useState([{name:'first'},{name:'second'},{name:'three'}])

       // Function to reverse a given array
        const reverseArray = (array) => {
          var reverseArray = array.reverse();
          return reverseArray;
        }


        return (
            <div>
                  {data.map((item,index)=>{
                         return <h1 key={index}>{item.name} index: {index}</h1>
                    })}
            

                    {/*When I click this I expect the div above to rerender */}
                    <button onClick={()=>{
                        var newData = data;
                        setData(reverseArray(newData))}
                    }>
                      Reverse Order
                     </button>

                    {/* Logs state to the console to check order is reversed */}
                    <button onClick={()=>console.log(data)}>Log Data</button>

                    {/* Clearing the state by setting to empty array */}
                    <button onClick={()=>setData([ ])}>Clear Data</button>

                    
            </div>
        )
    }

所以我的主要问题是映射数据似乎不会随着状态更新而改变。作为检查状态是否更新,我有一个清除按钮可以清除数据状态并且列表变为空白。 

当我单击反转按钮时,我希望数据被反转(即“第一个”在最后,“三个”在第一个位置)。我确定我的状态已更新,因为我可以在单击反向按钮之前和之后使用控制台日志检查它。

我的思考过程是创建一个全新的反向数组 (newData) 并将其设置为状态。但是,映射不反映此顺序更改。我在这里错过了什么? 

我知道 React 中的组件会在状态改变时重新渲染,为什么将新数组设置为状态不会触发这个?但是清除状态时重新渲染很明显?

我的沙箱:https : //codesandbox.io/s/immutable-sun-oujqj?file=/ src/ App.js

2个回答

演示: https : //codesandbox.io/s/array-reverse-react-state-0v67h

Array.prototype.reverse()反转元素到位。您需要将一个新数组传递到setData().

<button
  onClick={() => {
    var newData = data;

    // Create a new array using the spread operator
    setData(reverseArray([...newData])); 
  }}
>

React 没有重新渲染组件的原因是因为Array.prototype.reverse改变了数组并返回引用

例如

    const array = [1,2,3,4,5]
    const revArray = array.reverse() // This will reverse 'array' variable and returns it's reference
    
    array === revArray // this statement is true
    console.log(array) // result [5,4,3,2,1]
    console.log(revArray) // result [5,4,3,2,1]

在上面array === revArray因为两者都指的是同一个数组,既然是这样,状态实际上并没有改变,因为对数组的引用是相同的。

解决方案: 简单地返回一个新的数组!

 const reverseArray = (array) => {
      const revArray = array.reverse();
      return [...revArray] 
    }