Reputation: 44
I'm making a blog with posts that can be liked and saved to localstorage.
I get posts from api.
When you like, the color and the number of likes change. The function itself works. But when I like one post, after refreshing the page, all posts get likes. That is, localstorage does not work correctly, I think. For a long time I tried to fix it myself, but it turns out to be done. I hope for your help, friends.
Here is the code:
import React from 'react';
import { format } from 'date-fns';
import './BlogList.scss';
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
function BlogList({
key,
title,
tagList,
favoritesCount,
createdAt,
description,
favorited,
authorUserName,
authorImage,
}) {
const [likeCount, setLikeCount] = React.useState(() => {
const saved = localStorage.getItem('likeCount');
const initialValue = JSON.parse(saved);
return initialValue || favoritesCount;
});
const [liked, setLiked] = React.useState(() => {
const saved = localStorage.getItem('liked');
const initialValue = JSON.parse(saved);
return initialValue || favorited;
});
const likePost = () => {
setLiked(!liked);
// eslint-disable-next-line no-unused-expressions
setLikeCount(liked ? likeCount - 1 : likeCount + 1);
}
React.useEffect(() => {
localStorage.setItem('likeCount', JSON.stringify(likeCount));
localStorage.setItem('liked', JSON.stringify(liked))
});
const heartFill = liked ? 'crimson' : 'currentColor';
const createDate = format(new Date(createdAt), 'MMMM d, uu');
return (
<div key={key} className="blog-frame">
<div className="blog-frame__content">
<div className="blog-article">
<h5>{title}</h5>
<button type="button" className="like-btn" onClick={likePost}>
<FavoriteBorderIcon style={{ fill: heartFill }} />
</button>
<p className="like-count">
{likeCount}
</p>
</div>
{tagList.map((tag, idx) => {
return <button key={`${tag}-${idx}`} type="button" className="btn-blog-tag">{tag}</button>
})}
<p className="blog-frame__text">
{description}
</p>
</div>
<div className="blog-frame__profile">
<div className="profile-article">
<h6>{authorUserName}</h6>
<p className="profile-date">{createDate}</p>
</div>
<div className="profile-avatar"><img src={authorImage} alt="avatar" /></div>
</div>
</div>
)
}
export default BlogList;
My BlogContent component where my props are located
import React from 'react';
import BlogList from '../BlogList/BlogList';
import useFetchData from '../../services/useFetchData';
import './BlogContent.scss';
function BlogContent() {
const { posts } = useFetchData();
const dataposts = posts.map((post, index) => {
return (
// eslint-disable-next-line react/no-array-index-key
<React.Fragment key={index}>
<BlogList
post={post}
title={post.title}
tagList={post.tagList}
favoritesCount={post.favoritesCount}
createdAt={post.createdAt}
description={post.description}
favorited={post.favorited}
authorUserName={post.author.username}
authorImage={post.author.image}
/>
</React.Fragment>
);
});
return (
<div className="blog-list-wrapper">
{dataposts}
</div>
);
}
export default BlogContent;
I get posts from useFetchData:
import React from 'react';
import axios from 'axios';
const useFetchData = () => {
const [posts, setPosts] = React.useState([]);
React.useEffect(() => {
const fetchData = async () => {
try {
const { data: response } = await axios.get('http://kata.academy:8022/api/articles');
setPosts(response.articles);
} catch (error) {
console.error(error);
}
};
fetchData();
}, []);
return {
posts,
};
};
export default useFetchData;
I apologize for such details. Made everything clear to you. Thanks.
Upvotes: 0
Views: 620
Reputation: 619
Pass
[ likeCount , liked ]
to dependence list ofuseEffect
.By this every time the state changes it'll update the value in local storage. Load local storage only once whenever the page is rendered. Have a look at this code example
const [likeCount, setLikeCount] = React.useState('')
const [liked , setLiked] = React.useState('')
useEffect(()=>{
// calls only once
setLikeCount('localStorageVal')
setLiked ('localStorageVal')
}, [ ] )
useEffect(()=>{
// saves to local storage
}, [ liked , likeCount ] )
Upvotes: 1
Reputation: 1306
You have to store a pair of like counts and their respective ID. Right now you are just saving the like count and repopulating it in UI. Your code has no logic of how to determine which likes are for which posts.
// Try something like this
const mapoflikes = {};
// increase mapofLikes
mapofLikes[id] = mapofLikes[id]+1 ?? 1
// save this to localstorage
// retrieve this from localstorage.
Upvotes: 1