[英]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.