如何更新帖子数组中的单个帖子



如何对单个帖子进行评级,而不必重新获取所有帖子

目前我有一个数组的帖子,我通过映射。我给一个帖子评级,但每次都要重新取回所有的帖子。是否有一种方法,只取回我给评级的帖子?

在前端我有:

const [posts, setPosts] = useState([])

useEffect(() => {
allPosts()
}, [])

const allPosts = async () => {
try {

const { data } = await axios.get(`/posts/${page}`)
setPosts(data)
} catch (err) {
console.log(err)
}
}

const likePost = async (e, newValue) => {
e.preventDefault()
setValue1(newValue)
try {
const { data } = await axios.put('/like-post', {
likeId: currentPost._id,
hover,
})
} catch (err) {
console.log(err)
}
}

在后台我收集所有的帖子:

export const posts = async (req, res) => {
try {
const currentPage = req.params.page || 1
const perPage = 5
const posts = await Post.find()
.skip((currentPage - 1) * perPage)
.limit(perPage)
.populate('postedBy')
.populate('comments.postedBy', '_id name image')
.sort({ createdAt: -1 })
res.json(posts)
} catch (err) {
console.log(err)
}
}

Like the Post on the Frontend I am:

const [value1, setValue1] = useState(0)

const likePost = async (e, newValue) => {
e.preventDefault()
setValue1(newValue)
try {
const { data } = await axios.put('/like-post', {
likeId: currentPost._id,
hover,
})

allPosts()
} catch (err) {
console.log(err)
}
}

和喜欢端:

export const likePost = async (req, res) => {
try {
const { likeId, hover } = req.body
const user = await User.findById(req.user._id).exec()
const post = await Post.findById(likeId).exec()
// console.log(user.id)
let existingRatingObject = post.likes.find((ele) => ele.postedBy == user.id)
if (existingRatingObject === undefined) {
let ratingAdded = await Post.findByIdAndUpdate(
likeId,
{
$push: { likes: { starValue: hover, postedBy: user } },
},
{ new: true },
).exec()
res.json(ratingAdded)
} else {
// if user have already left rating, update it
const ratingUpdated = await Post.updateOne(
{ likes: { $elemMatch: existingRatingObject } },
{ $set: { 'likes.$.starValue': hover } },
{ new: true },
).exec()
res.json(ratingUpdated)
}
} catch (err) {
console.log(err)
}
}

如果你想触发重新渲染,你可以在父组件中声明likePost函数,并将其作为道具传递给Post组件。
这样做,你将能够访问setPosts方法并触发重新渲染。

在父组件中:


const likePost = async (e, newValue) => {
e.preventDefault();
setValue1(newValue);
try {
const { data } = await axios.put('/like-post', {
likeId: currentPost._id,
hover,
});

const postIndex = posts.indexOf((post) => post._id === data._id);
if (postIndex === -1) {
// Add new post
setPosts((oldData) => {
return [...oldData, data]
})
} else {
// Update post
setPosts((oldData) => {
oldData[postIndex] = data
return oldData
})
}
} catch (err) {
console.log(err);
}
};

...
{
posts.map((post) => (
<div key={post._id} className='mb-3'>
<Post post={post} likePost={likePost} />
</div>
));
}

然后,将您的Post组件声明更改为并从中删除likePost函数实现:

export default function Post({
post,
likePost
}) { ... }

Rating组件上的onChange方法定义将保持不变:

<Rating
size="large"
name="hover-feedback"
value={value1}
precision={0.5}
onChange={(e, newValue) => likePost(e, newValue)}
onChangeActive={(event, newHover) => {
setHover(newHover)
}}
onClick={() => handlePostID(post)}
emptyIcon={<StarIcon style={{ opacity: 0.55 }}fontSize="inherit"/>}
/>

下面是我的JSX。我将post映射到post,并且在post组件中我有一个loadLikes, showaaverage函数和likePost。

{posts.map((post) => (
<div key={post._id} className="mb-3">
<Post
post={post}
/>`

那么我有以下函数:

export default function post({
post,
}) {
const [state, setState] = useContext(UserContext)
const [hover, setHover] = useState(-1)
const [value1, setValue1] = useState(0)
const [postAverage, setPostAverage] = useState(0)

//UE - show likes
useEffect(() => {
if (state && state.token) {
loadLikes()
showAverage()
}
}, [state && state.token])

//V - Like Rating

const loadLikes = async () => {
console.log('load likes')
if (post.likes && state.user) {
let existingRatingObject = await post.likes.find(
(ele) => ele.postedBy == state.user._id,
)
existingRatingObject && setValue1(existingRatingObject.starValue) // current user's star
}
}

const showAverage = () => {
console.log('show average run')
if (post && post.likes && state.user) {
let likesArray = post.likes
let total = []
let length = likesArray.length
// console.log("length", length);

likesArray.map((r) => total.push(r.starValue))
let totalReduced = total.reduce((p, n) => p + n, 0)
// console.log("totalReduced", totalReduced);

let highest = length * 5
// console.log("highest", highest);

let average = (totalReduced * 5) / highest
// console.log("result", result);

setPostAverage(average)
// console.log('POST AVERAGE', postAverage)
}
}

const likePost = async (e, newValue) => {
e.preventDefault()
setValue1(newValue)
setAnchorEl(null)

try {
const { data } = await axios.put('/like-post', {
likeId: currentPost,
hover,
})
socket.emit('new-post', hover)

const postIndex = posts.indexOf(currentPost)
const newRatedPost = data.ratingUpdatedDetails
setPosts((oldData) => {
oldData[postIndex] = newRatedPost
return oldData
})

} catch (err) {
console.log(err)
}
}
return (
<>
<Rating
size="large"
name="hover-feedback"
value={value1}
precision={0.5}
onChange={(e, newValue) => likePost(e, newValue)}
onChangeActive={(event, newHover) => {
setHover(newHover)
}}
onClick={() => handlePostID(post)}
emptyIcon={<StarIcon style={{ opacity: 0.55 }}fontSize="inherit"/>}
/>
<>
)
}

我已经添加了oldData代码像你建议的,但这并没有渲染映射后的道具?不知道我能做什么更新吗?

@Ipizzinidev

最新更新