Skip to content

Commit e1383a8

Browse files
authored
fix: prevent stale timeout in CodeBlockWithCopy (#8005)
1 parent 4e1b128 commit e1383a8

1 file changed

Lines changed: 25 additions & 4 deletions

File tree

src/components/CodeBlockWithCopy/CodeBlockWithCopy.jsx

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import PropTypes from "prop-types";
2-
import { useRef, useState } from "react";
2+
import { useEffect, useRef, useState } from "react";
33
import "./CodeBlockWithCopy.scss";
44

55
export default function CodeBlockWithCopy({ children }) {
66
const preRef = useRef(null);
7+
const resetStatusTimeoutRef = useRef(null);
78
const [copyStatus, setCopyStatus] = useState("copy");
9+
810
const codeClassName =
911
typeof children?.props?.className === "string"
1012
? children.props.className
@@ -37,6 +39,16 @@ export default function CodeBlockWithCopy({ children }) {
3739
return clonedCodeElement.textContent || "";
3840
};
3941

42+
const scheduleResetStatus = () => {
43+
if (resetStatusTimeoutRef.current) {
44+
clearTimeout(resetStatusTimeoutRef.current);
45+
}
46+
47+
resetStatusTimeoutRef.current = setTimeout(() => {
48+
setCopyStatus("copy");
49+
}, 2000);
50+
};
51+
4052
const handleCopy = async () => {
4153
if (!preRef.current) return;
4254

@@ -47,13 +59,13 @@ export default function CodeBlockWithCopy({ children }) {
4759

4860
if (!codeText) {
4961
setCopyStatus("error");
50-
setTimeout(() => setCopyStatus("copy"), 2000);
62+
scheduleResetStatus();
5163
return;
5264
}
5365

5466
let successfulCopy = false;
5567

56-
// Try modern API (navigator.clipboard) -> as document.execCommand() deprecated
68+
// Try modern API (navigator.clipboard)
5769
try {
5870
if (navigator.clipboard && window.isSecureContext) {
5971
await navigator.clipboard.writeText(codeText);
@@ -85,9 +97,18 @@ export default function CodeBlockWithCopy({ children }) {
8597
}
8698

8799
setCopyStatus(successfulCopy ? "copied" : "error");
88-
setTimeout(() => setCopyStatus("copy"), 2000);
100+
scheduleResetStatus();
89101
};
90102

103+
useEffect(
104+
() => () => {
105+
if (resetStatusTimeoutRef.current) {
106+
clearTimeout(resetStatusTimeoutRef.current);
107+
}
108+
},
109+
[],
110+
);
111+
91112
return (
92113
<div className="code-block-wrapper">
93114
<button

0 commit comments

Comments
 (0)