[英]How can I update component in React after adding a new item into the database, using react hooks?
我想在添加存储到后端的新评论后更新组件,并使用具有新评论的新组件更新先前显示的组件。
这是加载单个帖子/文章及其评论的 Page.js :
import React ,{useState, useContext, useEffect}from 'react'; import {useHistory,Redirect, useParams} from 'react-router-dom' import axios from 'axios' import '../CSS/Page.css' import CreateComment from './CreateComment'; const Page=()=>{ const [show,setShow]=useState({ commentBox:false }) const [post,setPost] = useState( {id:'', username:'', title:'',body:'',date:'',comments:[{}] }) let {postTitle}=useParams() useEffect(() => { axios.get(`http://localhost:2000/apiEndpoint/singlePost/${postTitle}`,{withCredentials:true},{ headers: { 'Content-Type': 'application/json' } }).then((res)=>{ console.log(res.data) const postS=res.data setPost({...post,id:postS._id, username:postS.username, title:postS.title, body:postS.body,comments: postS.comments}) return; }).catch((err)=>{ console.log([err]) }) },[]); const handleCommentButton=(e)=>{ setShow({ ...show, commentBox:!show.commentBox }); } return ( <div className='postContainer'> <div className='singlePostcontainer'> <div className='singlePost' > <h1>{post.title}</h1> <hr/> <p>{post.body} </p> {post.id} <hr/> <h5>Comments:<button className='btnCom' onClick={handleCommentButton}>{show.commentBox?'Close':'Add Comment'}</button></h5> {show.commentBox?(<CreateComment post={post} />):''} {post.comments.map(comment=>{ const commentID=comment._id return( <div className='comment' key={commentID}> <h3>{comment.body}</h3> <h6>By: {comment.creater}</h6> </div> ) })} </div> </div> </div> ) } export default Page
这是 CreateComment.js组件,它有一个表单并向数据库发送请求:
import React, { Component,useState, useEffect, lazy } from 'react'; import Cookies from 'js-cookie'; import { Link, Redirect } from 'react-router-dom'; const axios = require('axios').default; const CreateComment=(props)=>{ var commentStr={ body:'' } const [comment, setComment] = useState(commentStr); const handleSubmitA=(e)=>{ e.preventDefault() console.log('This is the id:',props.post.id) axios.post(`http://localhost:2000/apiEndpoint/CREATE/comment/${props.post.id}`,{ body:comment.body }, {withCredentials:true},{ headers: { 'Content-Type': 'application/json' }}).then(res=>{ console.log(res); }) } const handleChangeA=(e)=>{ const {name,value}=e.target setComment({ ...comment, [name]: value }); } return( <div className='commentContainer'> <form onSubmit={handleSubmitA}> <label>Enter Comment</label> <textarea name="body" onChange={handleChangeA}></textarea> <button>Submit</button> </form> </div> ) } export default CreateComment
我能够成功添加组件,并且还将评论发布到后端数据库。 但它只在我按下重新加载时显示在页面上。
我从 useEffect 钩子内部删除了空数组。 它给了我一个无限循环,但工作正常。 但是,由于这不是一个好的做法,并且会占用本地存储资源,因此如何在没有无限循环的情况下执行相同的任务?
你可能有一个陈旧的关闭。 https://dmitripavlutin.com/react-hooks-stale-closures/
尝试这个:
setPost(prevState => ({
...prevState,
id: postS._id,
username: postS.username,
title: postS.title,
body: postS.body,
comments: postS.comments
}))
您实际上并没有在发表评论后更新帖子。
一个简单的解决方案是让<CreateComment />
接受一个回调,该回调可以向父级发出新评论可用的信号。 然后,父母可以决定如何处理该信息。 您可以触发对帖子的重新获取,以获取在用户处理评论时可能已登顶的所有其他评论和状态更新。
const CreateComment = (props) => {
const onSubmit = (e) => {
e.preventDefault();
console.log('This is the id:', props.post.id)
axios.post(`http://localhost:2000/apiEndpoint/CREATE/comment/${props.post.id}`, {
body: comment.body
}, {
withCredentials: true
}, {
headers: {
'Content-Type': 'application/json'
}
}).then(res => {
props.onCommentCreated();
});
};
};
如果您的 api 返回评论,您可以改为使用props.onCommentCreated(res.data)
将评论传递给父级。 然后您将不需要重新获取,因为父级只会将其推送到他们的评论状态切片中。
如果您想变得真正花哨,您可以考虑从组件中完全删除处理帖子/评论的逻辑,并将其全部粘贴到钩子中。 这使您的逻辑可重用。 它也更容易推理,因为usePost
钩子有一个很好定义的 api 并且所有的状态争论都发生在幕后。 我根本没有测试过这个,所以如果你走这条路,你将不得不调整它。
const EMPTY_POST = {
id: '',
username: '',
title: '',
body: '',
date: '',
comments: [{}]
}
const getPost = (title) => {
return axios.get(`http://localhost:2000/apiEndpoint/singlePost/${title}`, {
withCredentials: true
}, {
headers: {
'Content-Type': 'application/json'
}
}).then((res) => res.data);
};
const postComment = (id, content) => {
return axios.post(`http://localhost:2000/apiEndpoint/CREATE/comment/${id}`, {
body: content
}, {
withCredentials: true
}, {
headers: {
'Content-Type': 'application/json'
}
})
}
const usePost = () => {
const [post, setPost] = useState(EMPTY_POST);
const {
title
} = useParams();
const findPost = (title) => {
getPost(title)
.then((res) => {
const postS = res.data;
setPost({
...post,
id: postS._id,
username: postS.username,
title: postS.title,
body: postS.body,
comments: postS.comments
})
})
.catch((e) => {
console.log(":(", e);
});
};
useEffect(() => {
findPost(title)
}, []);
const createComment = (id, comment) => {
postComment(id, comment)
.then(() => findPosts(title)); // refetch?
postComment(id, comment)
.then((result) => {
setPost({ ...post, comments: [...post.comments, result]}));
}); // just include it in.
}
return {
post,
createComment
};
}
所以现在你的 post 逻辑在一个单一的钩子中,你可以像在你的组件中一样使用它。 这是一个显示可能实现的缩写版本。
const Page = () => {
const { post, createComment } = usePost();
return (
...
{show.commentBox && <CreateComment post={post} onSubmit={createComment } />}
...
};
const CreateComment = (props) => {
const { post, onSubmit } = props;
const [comment, setComment] = useState(commentStr);
const handleSubmit = (e) => {
e.preventDefault();
onSubmit(post.id, comment);
};
return (...);
};
顺便说一句,在未检查组件挂载状态的情况下在 Promise 中设置状态,如果组件在挂起的 Promise 处于活动状态时卸载会触发状态更新,则会在控制台中向您发出警告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.