I have a trivial example I built that shows the function passed into the second parameter of React.memo seems to not get the previous property value as I would expect. This example is a simple list of speakers (objects) that are rendered as buttons. The onClick event on the button caused passed up to the parent component, state changes in the parent, and a new render should show just the updated component.
However, regardless of the previous state, the passed in previous is always the same as the new state.
The example is at this URL: https://stackblitz.com/edit/react-upe9vu
In the component Hello.js the current import is for ./Speaker however, if you change that to ./SpeakerWithMemo as shown in the line above, the button click fails to update the "favorite" status.
I would expect that in SpeakerWithMemo.js that the console.log at line 12 would show the prevProps.speaker.favorite different then the nextProps.speaker.favorite.
The relevant code is below:
Hello.js
import React, { useState } from "react";
// NO UPDATE HAPPENS ON BUTTON CLICK.
//import Speaker from "./SpeakerWithMemo";
// UPDATE HAPPENS AS EXPECTED ON BUTTON CLICK
import Speaker from "./Speaker";
export default () => {
const speakersArray = [
{ name: "Crockford", id: 101, favorite: true },
{ name: "Gupta", id: 102, favorite: false },
{ name: "Ailes", id: 103, favorite: true },
];
const [speakers, setSpeakers] = useState(speakersArray);
const clickFunction = (speakerIdClicked) => {
var speakersArrayUpdated = speakers.map((rec) => {
if (rec.id === speakerIdClicked) {
rec.favorite = !rec.favorite;
}
return rec;
});
setSpeakers(speakersArrayUpdated);
};
return (
<div>
{speakers.map((rec) => {
return (
<Speaker
speaker={rec}
key={rec.id}
clickFunction={() => {
clickFunction(rec.id);
}}
></Speaker>
);
})}
</div>
);
};
SpeakerWithMemo.js
import React from "react";
export default React.memo(
({ speaker, clickFunction }) => {
console.log(`Rendering Speaker ${speaker.name} ${speaker.favorite}`);
return (
<button onClick={clickFunction}>
With Memo {speaker.name} {speaker.id}{" "}
{speaker.favorite === true ? "true" : "false"}
</button>
);
},
(prevProps, nextProps) => {
console.log(
`memo: ${prevProps.speaker.favorite === nextProps.speaker.favorite} ${
prevProps.speaker.name
} fav: prev: ${prevProps.speaker.favorite} next: ${
nextProps.speaker.favorite
} `
);
return prevProps.speaker.favorite === nextProps.speaker.favorite;
}
);