【问题标题】:Getting this error when replying to comment: Can't perform a React state update on an unmounted component回复评论时出现此错误:Can't perform a React state update on an unmounted component
【发布时间】:2022-06-10 17:58:46
【问题描述】:

我在回复评论或删除评论时收到此错误消息。

index.js:1 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in ReplyForm (at CommentReply.js:95)

我没有使用 useEffect 钩子,它仍然在说 “在 useEffect 清理函数中取消所有订阅和异步任务:”。 任何人,请帮我解决这个错误!

评论回复.js

import React from "react"
import moment from "moment"
import { useParams } from "react-router-dom"

import { useAuthContext } from "../../hooks/useAuthContext"
import { useFirestore } from "../../hooks/useFirestore"

import ReplyForm from "./ReplyForm"

const CommentReply = ({
  comment,
  parentReplies,
  activeComment,
  setActiveComment,
  parentId = null,
}) => {
  const { updateSubCollectionDocument } = useFirestore("solutions")
  const { id: docID } = useParams()

  const { user } = useAuthContext()

  const isReplying =
    activeComment && activeComment.id === comment.id && activeComment.type === "replying"
  const replyId = parentId || comment.id

  // handle sub collection document
  const handleDelete = async () => {
    if (window.confirm("Do you really want to delete this reply?")) {
      const updatedReplies = parentReplies.filter((reply) => reply.id !== comment.id)
      await updateSubCollectionDocument(docID, parentId, {
        replies: updatedReplies,
      })
    }
  }

  return (
    <div className="my-4 border border-gray-800 rounded p-4">
      <div className="flex">
        <a
          href={`https://github.com/${comment.user.username}`}
          target="_blank"
          rel="noopener noreferrer"
        >
          <img
            className="w-12 rounded-full border-2 border-gray-800"
            src={comment.user.avatarURL}
            alt="avatar"
          />
        </a>
        <div className="ml-4 flex-1">
          <p className="text-gray-300 mb-2">
            <a
              href={`https://github.com/${comment.user.username}`}
              target="_blank"
              rel="noopener noreferrer"
            >
              {comment.user.displayName
                ? comment.user.displayName
                : comment.user.username}
            </a>
            <small className="pl-2 text-gray-400">
              {moment(comment.createdAt.toDate()).fromNow()}
            </small>
          </p>
          <div className="mt-2 flex">
            {user && (
              <button
                onClick={() => setActiveComment({ id: comment.id, type: "replying" })}
                className="text-gray-400"
              >
                <i className="fas fa-reply"></i>
                <small className="pl-2 font-semibold">Reply</small>
              </button>
            )}
            {user?.uid === comment.user.userID && (
                <button className="text-gray-400" onClick={handleDelete}>
                  <i className="fas fa-trash-alt"></i>
                  <small className="pl-2 font-semibold">Delete</small>
                </button>
            )}
          </div>
          {isReplying && (
            <ReplyForm
              docID={docID}
              replyingTo={comment.user.username}
              id={replyId}
              replies={parentReplies}
              hasCancelButton
              setActiveComment={setActiveComment}
            />
          )}
        </div>
      </div>
    </div>
  )
}

export default CommentReply

ReplyForm.js

import React, { useState } from "react"
import { Timestamp } from "firebase/firestore"
import { v4 as uuidv4 } from "uuid"

import { useAuthContext } from "../../hooks/useAuthContext"
import { useFirestore } from "../../hooks/useFirestore"

const ReplyForm = ({
  docID,
  replyingTo,
  id,
  commentID,
  replies,
  setActiveComment,
  initialText = "",
  isReply,
  hasCancelButton = false,
}) => {
  const [newComment, setNewComment] = useState(initialText)
  const { updateSubCollectionDocument, response } = useFirestore("solutions")
  const { user } = useAuthContext()

  const handleSubmit = async (e) => {
    e.preventDefault()

    try {
      const commentToAdd = {
        id: uuidv4(),
        content: newComment.trim(),
        reactions: [],
        replyingTo,
        parentID: id,
        user: {
          userID: user.uid,
          avatarURL: user.photoURL,
          displayName: user.displayName,
          username: user.reloadUserInfo.screenName,
        },
        createdAt: Timestamp.now(),
      }

      if (!isReply && initialText) {
        await updateSubCollectionDocument(docID, id, {
          content: newComment,
        })
      } else if (isReply && initialText) {
        const reply = replies.find((reply) => reply.id === commentID)
        if (reply) reply.content = newComment
        await updateSubCollectionDocument(docID, id, {
          replies: replies,
        })
      } else {
        await updateSubCollectionDocument(docID, id, {
          replies: [...replies, commentToAdd],
        })
      }
      setActiveComment(false)
      setNewComment("")
    } catch (error) {
      console.log(error)
    }
  }

  return (
    <form className="flex flex-col" onSubmit={handleSubmit}>
      <label htmlFor="reply">
        <textarea
          className="bg-transparent text-white font-semibold border border-gray-800 rounded w-full p-4 mt-6 outline-none focus:ring-1 focus:ring-purple-500"
          name="reply"
          id="reply"
          cols="30"
          rows="4"
          placeholder="Start Typing..."
          required
          onChange={(e) => setNewComment(e.target.value)}
          value={newComment}
        ></textarea>
      </label>
      <div className="flex">
        <button
          className={`self-end ${
            response.isPending
              ? "bg-indigo-500 cursor-not-allowed"
              : "bg-purple-800 transition-all duration-200 bg-gradient-to-br hover:from-purple-500 hover:to-indigo-500"
          } mt-4 p-3 text-white text-base font-heading font-semibold shadow-md rounded focus:outline-none`}
          disabled={response.isPending}
        >
          Reply
        </button>
        {hasCancelButton && (
          <button
            onClick={() => setActiveComment(false)}
            type="button"
            className={`self-end bg-purple-800 transition-all duration-200 bg-gradient-to-br hover:from-purple-500 hover:to-indigo-500 mt-4 ml-4 p-3 text-white text-base font-heading font-semibold shadow-md rounded focus:outline-none`}
          >
            Cancel
          </button>
        )}
      </div>
    </form>
  )
}

export default ReplyForm

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    谈到你的sn-ps中的功能组件从父组件调用setActiveComment(false),状态isActive必须用于CommentReply.js的条件渲染。下一次调用setNewComment("") 在同一个组件内。 这些重新渲染将卸载它无法执行的子组件setNewComment("")


    如果是,修复可以, 您最好删除 setNewComment("") 并将其放入带有空依赖数组的 useEffect() 中,以便在组件第一次安装而不是重新渲染时设置空字符串。

    ReplyForm.js

    
    import React, { useState } from "react"
    import { Timestamp } from "firebase/firestore"
    import { v4 as uuidv4 } from "uuid"
    
    import { useAuthContext } from "../../hooks/useAuthContext"
    import { useFirestore } from "../../hooks/useFirestore"
    
    const ReplyForm = ({
      docID,
      replyingTo,
      id,
      commentID,
      replies,
      setActiveComment,
      initialText = "",
      isReply,
      hasCancelButton = false,
    }) => {
      const [newComment, setNewComment] = useState(initialText)
      const { updateSubCollectionDocument, response } = useFirestore("solutions")
      const { user } = useAuthContext();
    
      useEffect(()=>{
        setNewComment("");
      },[]);
    
      const handleSubmit = async (e) => {
        e.preventDefault()
    
        try {
          const commentToAdd = {
            id: uuidv4(),
            content: newComment.trim(),
            reactions: [],
            replyingTo,
            parentID: id,
            user: {
              userID: user.uid,
              avatarURL: user.photoURL,
              displayName: user.displayName,
              username: user.reloadUserInfo.screenName,
            },
            createdAt: Timestamp.now(),
          }
    
          if (!isReply && initialText) {
            await updateSubCollectionDocument(docID, id, {
              content: newComment,
            })
          } else if (isReply && initialText) {
            const reply = replies.find((reply) => reply.id === commentID)
            if (reply) reply.content = newComment
            await updateSubCollectionDocument(docID, id, {
              replies: replies,
            })
          } else {
            await updateSubCollectionDocument(docID, id, {
              replies: [...replies, commentToAdd],
            })
          }
          setActiveComment(false);
        } catch (error) {
          console.log(error);
        }
      }
    
      return (
        <form className="flex flex-col" onSubmit={handleSubmit}>
          <label htmlFor="reply">
            <textarea
              className="bg-transparent text-white font-semibold border border-gray-800 rounded w-full p-4 mt-6 outline-none focus:ring-1 focus:ring-purple-500"
              name="reply"
              id="reply"
              cols="30"
              rows="4"
              placeholder="Start Typing..."
              required
              onChange={(e) => setNewComment(e.target.value)}
              value={newComment}
            ></textarea>
          </label>
          <div className="flex">
            <button
              className={`self-end ${
                response.isPending
                  ? "bg-indigo-500 cursor-not-allowed"
                  : "bg-purple-800 transition-all duration-200 bg-gradient-to-br hover:from-purple-500 hover:to-indigo-500"
              } mt-4 p-3 text-white text-base font-heading font-semibold shadow-md rounded focus:outline-none`}
              disabled={response.isPending}
            >
              Reply
            </button>
            {hasCancelButton && (
              <button
                onClick={() => setActiveComment(false)}
                type="button"
                className={`self-end bg-purple-800 transition-all duration-200 bg-gradient-to-br hover:from-purple-500 hover:to-indigo-500 mt-4 ml-4 p-3 text-white text-base font-heading font-semibold shadow-md rounded focus:outline-none`}
              >
                Cancel
              </button>
            )}
          </div>
        </form>
      )
    }
    
    export default ReplyForm
    

    【讨论】:

      猜你喜欢
      • 2022-06-10
      • 2021-05-05
      • 2019-10-29
      • 2020-05-15
      • 2020-01-15
      • 2022-01-11
      • 2021-03-25
      • 2020-06-28
      • 2020-09-10
      相关资源
      最近更新 更多