I'm displaying cards
with a map function on my state.
The state looks like this:
[{ position: "0", state: "pending" },
{ position: "1", state: "pending" },
{ position: "2", state: "pending" }]
In a function, I'm changing the "state" from "pending" to "right", but it does not refresh anything on the page.
export const Card: React.FC<ICardOwnProps> = ({ }) => {
const [rollingCards, setRollingCards] = useState<IRollingCard[]>([{ position: "0", state: "pending" }, { position: "1", state: "pending" }, { position: "2", state: "pending" }])
const handleClick = () => {
let newArray = rollingCards;
newArray.splice(0, 1)
setRollingCards(newArray);
}
useEffect(() => { console.log("check changes") })
return (
<StyledCard className="Card">
{rollingCards.map((v, i, a) =>
<Container key={i} className={"position" + v.position} >{v.state}</Container>
)}
<div className="card__container--button">
<button onClick={handleClick}>Oui</button>
<button>Non</button>
{rollingCards[0].state}
</div>
</StyledCard>
);
}
From now, nothings changes, but when I add a new state piece that I update at the same time as the rollingCards, it'll update. I added a counter, and with that, it updates the page.
(I also tried to splice the array to see if React would update, it did not)
Any idea why I've got this weird behavior ?
Thanks.
This is because React does a referential equality comparison of props/state when making a decision to rerender.
newArray has the same reference as rollingCards due to which the functional component does not re render on setRollingCards
Change
setRollingCards(newArray)
to
setRollingCards([...newArray])
This creates a new array (new reference) with the elements from newArray
Working solution: https://codesandbox.io/s/admiring-wave-9kgqq
Because react uses Object.is
to determine if the state has changed.
In your code, newArray
is the same reference as rollingCards
, you can use Object.is(newArray, rollingCards)
to check.
const handleClick = () => {
let newArray = rollingCards;
newArray.splice(0, 1) // Object.is(newArray, rollingCards) is true
setRollingCards(newArray);
}
So you can change it like this.
setRollingCards(rollingCards.filter((item, index) => index !== 0);
Not only this method, as long as it is a different reference
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With