【发布时间】:2021-08-30 22:31:59
【问题描述】:
请帮我弄清楚为什么事件监听器的回调会执行两次:因为我需要离开cmets这样的功能,但是当我点击发布按钮时,回调会立即执行两次。我尝试添加加倍防止器,在 useState 中声明 cllciked var,但它无论如何都没有帮助。即使我单击提交按钮而不是双击,也会发生这种情况。
这是我的组件的代码:
export default function SpecificPostCommentsExtended({ article }) {
const [prev, setPrev] = useState("");
const [loaded, setLoaded] = useState(false);
const [clicked, setClicked] = useState(false);
const [comments, setComments] = useState([]);
const [newArticle, setNewArticle] = useState(false);
async function changePrevState(_id) {
setPrev(_id);
console.log(_id, "-is id");
console.log(await prev, "- prev");
}
const ifNoCom = async () => {
setComments([]);
setLoaded(true);
setTimeout(() => {
document.querySelector("#confirm").addEventListener("click", async () => {
if(!clicked) {
setClicked(true);
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,
},
},
});
if(typeof data != "object") {
return cogoToast.error("Please sign in first!")
}
setLoaded(true);
setPrev("");
setClicked(true);
console.log(data);
}
else {
cogoToast.warn("Already commenting...")
}
});
}, 30);
};
const ifCom = async () => {
setComments([]);
let i = 0;
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(typeof data != "object") {
return cogoToast.error("Please sign in first!")
}
if (!comments.includes({ ...data })) {
setComments((current) => [...current, { ...data }]);
}
i++;
if (i >= article.commentsArr.length - 1) {
setLoaded(true);
console.log("COMMENTS", comments);
setTimeout(() => {
document
.querySelector("#confirm")
.addEventListener("click", async () => {
if(!clicked) {
setClicked(true);
console.log("It's prev - ", prev, "!lalalal");
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,
},
},
});
setPrev("");
setClicked(false);
}
else {
cogoToast.warn("Already commenting...")
}
});
}, 30);
}
});
};
const getComments = async () => {
setComments([]);
setLoaded(false);
if (article.commentsArr.length === 0) {
ifNoCom();
} else {
ifCom();
}
};
useEffect(() => {
getComments();
}, [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);
window.location = "/mzs-general";
}}
>
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,
},
});
cogoToast.success(data);
}}
>
<img src="../../assets/likes.png" /> Likes {article.likes}
</span>
</div>
<div>
<span
onClick={async () => {
const { data } = await axios({
url: vars.BACKENDURL + "/like",
method: "POST",
withCredentials: true,
data: {
post: article,
},
});
alert(data);
}}
>
Like
</span>
<span>|</span>
<span
onClick={async () => {
const { data } = await axios({
url: vars.BACKENDURL + "/report",
method: "POST",
withCredentials: true,
data: {
post: article,
},
});
alert(data);
}}
>
Report
</span>
</div>
</LowerRightFrame>
<CommentsBlock id="commentsblock">
{comments.length === 0 ? (
<>No comments yet</>
) : (
comments.map((c, i) => {
return (
<>
<Comment key={i}>
<Nickname>{c.comment.author}</Nickname>
<Contents>{c.comment.content}</Contents>
<LowerCommentContainer>
<span>{c.comment.date}</span>
<span
onClick={(e) => {
changePrevState(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>
</>
);
}
【问题讨论】:
-
乍一看,您是在添加事件侦听器,但并未删除它们。此外,DOM 操作/查询是 React 中的反模式。要么使用 React ref 来访问任何 DOMNode,要么将事件处理程序直接附加到元素。现在深入挖掘。
-
我现在尝试直接附加事件监听器,谢谢你,Drew!
-
是的,看起来每个渲染周期都为
onClick组件添加了越来越多的onClick侦听器。在ifCom中,您将它们添加到一个循环中,因此如果在初始渲染中article.commentsArr数组中有两个元素,您将添加 2 个侦听器。 -
它有帮助,德鲁!现在一切正常! :)
标签: javascript reactjs react-router jsx