首页 > 解决方案 > 反应useState变量未设置

问题描述

我需要从数据库中显示关于 React 的评论和子评论,这些评论和子评论是通过 axios 调用我的后端 Express 服务器获得的。我在开发“回复评论”部分时遇到问题。我的 mongodb 模型是 author.email 作为作者,prevId 作为 prev 评论和内容!我已经开发了这样一个功能来在点击回复另一条评论时设置prev id。但是 prev 不会将其状态保持为字符串,它首先被设置,然后回退到“”。

我如何声明一个 USESTATE VAR 以确保一切正常?

RESULT COMMENTS ARR Array(0)
SpecificPostCommentsExtended.js:388 Objectcomment: {prevId: null, _id: "60c6cb3d23961520f85c23e2", content: "hello", author: "mailmai@me.co", date: "2021-06-14T03:21:33.248Z", …}subcomments: []__proto__: Object
SpecificPostCommentsExtended.js:532 C comment id 60c6cb0b23961520f85c23e0
SpecificPostCommentsExtended.js:532 C comment id 60c6cb2223961520f85c23e1
SpecificPostCommentsExtended.js:532 C comment id 60c6cb3d23961520f85c23e2
SpecificPostCommentsExtended.js:392 COMMENTS GET EDITED

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
export default function SpecificPostCommentsExtended({ article }) {
  const [prev, setPrev] = useState("");
  const [loaded, setLoaded] = useState(false);
  const [comments, setComments] = useState([]);
useEffect(() => {
  alert("prev changed", prev)

}, [prev]) 
  useEffect(async () => {
    setComments([]);
    let i = 0;
    setLoaded(false);
    if (article.commentsArr.length === 0) {
      setLoaded(true);
        alert("checkpoint 1")
        console.log("one sec");
        console.log("two sec")
        setTimeout(function () {
          document
          .querySelector("#confirm")
          .addEventListener("click", async () => {
            alert("comment")
            const data = await axios({
              url: vars.BACKENDURL + "/comment",
              withCredentials: true,
              method: "POST",
              data: {
                article: article,
                comment: {
                  content: document.querySelector("#commentcontent").value,
                  prevId: prev === "" ? null : prev,
                },
              },
            });
          setLoaded(true);
        })
      }, 30)
      return;
    }
    await article.commentsArr.forEach(async (c) => {
      const { data } = await axios({
        url: vars.BACKENDURL + "/getcomment",
        withCredentials: true,
        method: "POST",
        data: { comment: { _id: c } },
      });
      console.log(data)
      if (!comments.includes({ ...data })) {
        setComments(current => [...current, { ...data }]);
      }
      console.log("COMMENTS GET EDITED", ...comments);
      i++;
      if (i === article.commentsArr.length - 1) {
        setLoaded(true);
        console.log("RESULT COMMENTS ARR", comments);
        document
          .querySelector("#confirm")
          .addEventListener("click", async () => {
            alert("It's prev", prev)
            const data = await axios({
              url: vars.BACKENDURL + "/comment",
              withCredentials: true,
              method: "POST",
              data: {
                article: article,
                comment: {
                  content: document.querySelector("#commentcontent").value,
                  prevId: prev === "" ? null : prev,
                },
              },
            });
          });
      }
    });
  }, []);
  return (
    <>
      <Header>
        <HeaderImg src="../../assets/headerpic.png" />
        <Navbar>
          <span>mypage</span>| <span>log out</span>
        </Navbar>
      </Header>
      <Content>
        <SideBar />
        <RightFrame>
          {loaded === false ? (
            <CircularProgress />
          ) :  (
            <>
              <UpperBlock>
                <Title>
                  {article.group.toLowerCase()}
                  <Subtitle>
                    <span>previous</span>
                    <span>next</span>
                    <span>list</span>
                  </Subtitle>
                </Title>

                <PostContainer>
                  <PostDecription>
                    <div className="left">
                      <h2>{article.title}</h2>
                      <span>{article.writer}</span>
                      <span>{article.date}</span>
                    </div>
                    <div className="right">
                      <span
                        onClick={async () => {
                          window.location = `/${article._id}/edit`;
                        }}
                      >
                        edit
                      </span>
                      <span>|</span>
                      <span
                        onClick={async () => {
                          if (
                            !window.confirm(
                              "Are you sure you want to delete this post?"
                            )
                          ) {
                            return;
                          }
                          const { data } = await axios({
                            url: vars.BACKENDURL + `/deletepost`,
                            withCredentials: true,
                            method: "DELETE",
                            data: {
                              post: {
                                id: article._id,
                              },
                            },
                          });
                          alert(data);
                        }}
                      >
                        delete
                      </span>
                    </div>
                  </PostDecription>
                  <PostContents>
                    <h3>Contents</h3>
                    <p>{article.content}</p>
                  </PostContents>
                </PostContainer>
              </UpperBlock>
              <LowerBlock>
                <ReportBtns>
                  <ReportBtnMock>inappropriate language</ReportBtnMock>
                  <ReportBtnMock>misinformation</ReportBtnMock>
                </ReportBtns>
                <LowerRightFrame>
                  <div>
                    <span
                      onClick={() => {
                        window.location = "/specificpost/" + article._id;
                      }}
                    >
                      <img src="../../assets/comments.png" /> Comments{" "}
                      {article.comments}
                    </span>

                    <span
                      onClick={async () => {
                        const { data } = await axios({
                          url: vars.BACKENDURL + "/like",
                          method: "POST",
                          withCredentials: true,
                          data: {
                            post: article,
                          },
                        });
                        alert(data);
                      }}
                    >
                      <img src="../../assets/likes.png" /> Likes {article.likes}
                    </span>
                  </div>
                  <div>
                    <span>Like</span>
                    <span>|</span>
                    <span>Report</span>
                  </div>
                </LowerRightFrame>
                <CommentsBlock>
                  {comments.map((c, i) =>

                      {
                        console.log("C comment id", c.comment._id)
                        return (<><Comment key={i}>
                        <Nickname>{c.comment.author}</Nickname>
                        <Contents>{c.comment.content}</Contents>
                        <LowerCommentContainer>
                          <span>{c.comment.date}</span>
                          <span
                            onClick={() => {
                              setPrev(c.comment._id);
                              console.log(c.comment._id, "prev", prev)
                              window.alert(c.comment._id)
                            }}
                          >
                            reply
                          </span>
                        </LowerCommentContainer>
                      </Comment>
                      {

                        c.subcomments.map((sc, j) => {
                          return (<SubComment key={j}>
                        <Nickname>{sc.author}</Nickname>
                        <Contents>@{sc.author}, <br/> {sc.content}</Contents>
                        <LowerCommentContainer>
                          <span>{sc.date}</span>
                        </LowerCommentContainer>
                      </SubComment>)
                        })
                      }
                      </>
                      )}
                   )}
                  <ContentsInput id="commentcontent" />
                  <Confirm id="confirm">Post</Confirm>
                </CommentsBlock>
              </LowerBlock>
            </>
          )}
        </RightFrame>
      </Content>
    </>
  );
}

标签: javascriptreactjsreact-hooksjsxuse-state

解决方案


首先,useEffect不应该有一个async函数作为回调。上面的函数可以这样拆分。

const createComment = async () => {
        setLoaded(true);
        alert("checkpoint 1")
        console.log("one sec");
        console.log("two sec")
        setTimeout(function () {
            document
                .querySelector("#confirm")
                .addEventListener("click", async () => {
                    alert("comment")
                    const data = await axios({
                        url: vars.BACKENDURL + "/comment",
                        withCredentials: true,
                        method: "POST",
                        data: {
                            article: article,
                            comment: {
                                content: document.querySelector("#commentcontent").value,
                                prevId: prev === "" ? null : prev,
                            },
                        },
                    });
                    setLoaded(true);
                })
        }, 30)
        return;
    }
    const anotherAsyncFunction = async () => {
        await article.commentsArr.forEach(async (c) => {
            const { data } = await axios({
                url: vars.BACKENDURL + "/getcomment",
                withCredentials: true,
                method: "POST",
                data: { comment: { _id: c } },
            });
            console.log(data)
            if (!comments.includes({ ...data })) {
                setComments(current => [...current, { ...data }]);
            }
            console.log("COMMENTS GET EDITED", ...comments);
            i++;
            if (i === article.commentsArr.length - 1) {
                setLoaded(true);
                console.log("RESULT COMMENTS ARR", comments);
                document
                    .querySelector("#confirm")
                    .addEventListener("click", async () => {
                        alert("It's prev", prev)
                        const data = await axios({
                            url: vars.BACKENDURL + "/comment",
                            withCredentials: true,
                            method: "POST",
                            data: {
                                article: article,
                                comment: {
                                    content: document.querySelector("#commentcontent").value,
                                    prevId: prev === "" ? null : prev,
                                },
                            },
                        });
                    });
            }
        });
    }
    useEffect(() => {
        setComments([]);
        let i = 0;
        setLoaded(false);
        if (article.commentsArr.length === 0) {
            createComment();
        }
        anotherAsyncFunction()
    }, []);

它仍然不完美。如果您看到该anotherAsyncFunction功能,则不能以await这种方式在 Promises 数组上使用。应利用Promise.all()

此外,直接在 React 中访问 DOM 也不是一个好习惯。使用useRef或将 UI 逻辑更改为类似的东西(https://qcode.in/learn-react-by-creating-a-comment-app/https://letsbuildui.dev/articles/how-to-build -an-expandable-comment-box )


推荐阅读