簡體   English   中英

在將新項目添加到數據庫后,如何使用 React 鈎子更新 React 中的組件?

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM