繁体   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