问题
This is part of a larger component but I've summarised it in a reproducible example below:
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>
)
}
So my main issue, is that the mapped data doesn't seem to change with a state update. As a check that state does update, I have a clear button which does clear the data state and the list goes blank.
When I click the reverse button, I expect the data to be reversed (i.e. "first" to be last and "three" to be in first place). I'm sure my state is updated as I can check it with console logs before and after the reverse button is clicked.
My thought process was to create a completely new reversed array (newData) and set this as the state. However, the mapping doesn't reflect this order change. What am I missing here?
I understand components in React will rerender when state changes, why does setting a new array to state not trigger this? But the rerender is apparent when clearing the state?
My sandbox for this: https://codesandbox.io/s/immutable-sun-oujqj?file=/src/App.js
回答1:
Demo: https://codesandbox.io/s/array-reverse-react-state-0v67h
Array.prototype.reverse() reverses the elements in place. You'll need to pass a new array into setData()
.
<button
onClick={() => {
var newData = data;
// Create a new array using the spread operator
setData(reverseArray([...newData]));
}}
>
回答2:
The reason React is not re-rendering the component is because Array.prototype.reverse
mutates the array and return the reference
For Example
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]
In the above array === revArray
because both are referring to the same array,
Since that is the case, The state is not actually changing because the referrence to the array is same.
Solution: Simply return a new Array!
const reverseArray = (array) => {
const revArray = array.reverse();
return [...revArray]
}
来源:https://stackoverflow.com/questions/65689646/reversing-an-array-stored-in-state-doesnt-force-re-render-of-component-in-react