I have a list component that rendered by the Map, this is how I define the data in react function component:
const [projMap, setProjMap] = useState<Map<number, FolderModel>>(new Map<number, FolderModel>());
When I set the map in react function component like this:
React.useEffect(() => {
if (folderProjList && folderProjList.length > 0) {
if (currFolder) {
let cachedExpand = projMap.get(currFolder.id)?.expand;
let folderModel: FolderModel = {
expand: cachedExpand ? cachedExpand : true,
projects: folderProjList
};
projMap.set(currFolder.id, folderModel);
setProjMap(projMap);
}
}
}, [folderProjList]);
did not trigger the rerender where using the projMap to render UI. Then I change the style like this:
React.useEffect(() => {
if (folderProjList && folderProjList.length > 0) {
if (currFolder) {
setProjMap((prevMapState) => {
const newMapState = new Map<number, FolderModel>(prevMapState);
let cachedExpand = newMapState.get(currFolder.id)?.expand;
let folderModel: FolderModel = {
expand: cachedExpand ? cachedExpand : true,
projects: folderProjList
};
newMapState.set(currFolder.id, folderModel);
return newMapState;
});
}
}
}, [folderProjList]);
the rerender works fine. the UI was always keep to newest. what is the different with the two type of setState? why the second style works with immediate rerender but the fisrt style did not?
2
Answers
In the first one you’re mutating the map (by adding an entry) and then setting the mutated map as state, so the state didn’t actually change (referentially), it’s the same map, it just got mutated. When the state doesn’t referentially change, react doesn’t re-render.
In the second example, you’re creating a new map and setting the new map as state, no mutation, referentially different.
Don’t mutate state.
In the first example, you are only mutating the Map. Map is a reference type of data meaning adding or removing something from the it will not trigger React update.
Consider this small example
At the same time if you do something like this
React only does a shallow comparison like above to understand whether it requires a rerender or not.
So, if you want to update the state so that React does a rerender, you have to create a new instance. Your 1st example can also be reused like this