javascript - 反应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>
</>
);
}
解决方案
首先,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 )
推荐阅读
- android - 如何在 TextView 自己的容器中居中文本?
- conda - 使用 conda 更新 conda 的 UnsatisfiableError
- google-apps-script - Google Apps 脚本中的 MailApp.sendEmail() 不发送电子邮件
- tizen - 由于签名错误,设备上的应用程序安装失败 - tizen studio
- android - 运行牛轧糖的华为手机出现安全异常
- javascript - 如何检查日期时间?
- javascript - const path = require('path') -- 意外标识符
- java - 使用可选映射和过滤器重写 if 语句
- django - 有人可以解释为什么我需要在 Django 中引用两个模型吗?
- javascript - 使用用户输入更改或更新复选框值