I’m having an issue with all elements being re-rendered when saving favorite post variables. Here is an example of my code:
//....
const { data: favoritePosts, isLoading: favoritePostsLoading } = useSWR(
"https://jsonplaceholder.typicode.com/posts?_start=2&_limit=2",
fetcher,
);
const { mutate } = useSWRConfig();
const addFavorite = useCallback(
(post, isFavorite) => {
const { id } = post;
if (isFavorite) {
const newFavList = favoritePosts.filter((item) => item.id !== id);
mutate("https://jsonplaceholder.typicode.com/posts?_start=2&_limit=2", newFavList, {
revalidate: false,
});
return;
}
mutate("https://jsonplaceholder.typicode.com/posts?_start=2&_limit=2", [...favoritePosts, post], {
revalidate: false,
});
},
[favoritePosts],
);
//....
posts.map((post, index) => {
const isActive = currentPost && currentPost.id === post.id;
const isFavorite = favoritePosts.some(
(favoritePost) => favoritePost.id === post.id,
);
return (
<RenderPost
post={post}
addFavorite={addFavorite}
isFavorite={isFavorite}
key={post.id}
/>
)
})
const RenderPost = observer(
({ post, addFavorite, isFavorite }) => {
console.log("рендер");
return (
<div>
<div
style={{
marginBottom: "20px",
color: isFavorite ? "red" : "white",
}}
key={post.id}
>
<p>userId: {post.userId}</p>
<p>id: {post.id}</p>
<p>title: {post.title}</p>
<p>body: {post.body}</p>
<button onClick={() => addFavorite(post, isFavorite)}>
Add Favorite
</button>
</div>
</div>
);
},
);
After changing favoritePosts, all elements are rerendered. As I understand it, this is due to a change in the favoritePosts dependency. How can I avoid this rerender when changing only one element in the favoritePosts list?
I also utilized MobX and achieved the desired outcome. Upon receiving data, I store it in MobX using:
statePosts.setFavoritePosts(favoritePosts);
Here’s the corresponding function in MobX:
addFavorite = (post, isFavorite) => {
const { id } = post;
if (isFavorite) {
// Removing from favorites
const newFavList = this.favoritePosts.filter((item) => item.id !== id);
mutate("https://jsonplaceholder.typicode.com/posts?_start=2&_limit=2", newFavList, {
revalidate: false,
});
return;
}
mutate("https://jsonplaceholder.typicode.com/posts?_start=2&_limit=2", [...this.favoritePosts, post], {
revalidate: false,
});
}
The re-render occurs only once in the element where the state changed. However, I’m not comfortable with the idea of storing the same data in two places, in the SWR cache and in MobX. How can I achieve the same behavior without MobX?
Link to sandbox with full code:
https://codesandbox.io/p/devbox/twilight-moon-forked-ksn6cl?file=%2Fapp%2FPosts.jsx%3A56%2C9-56%2C20&workspaceId=e659ab19-3be8-46d2-a433-3e1d968b3bab