diff --git a/frontend/src/components/Preview.tsx b/frontend/src/components/Preview.tsx
index de8c36f..4728a73 100644
--- a/frontend/src/components/Preview.tsx
+++ b/frontend/src/components/Preview.tsx
@@ -1,13 +1,17 @@
+import useThrottle from "../hooks/useThrottle";
+
interface Props {
code: string;
}
function Preview({ code }: Props) {
+ const throttledCode = useThrottle(code, 200);
+
return (
diff --git a/frontend/src/hooks/useThrottle.ts b/frontend/src/hooks/useThrottle.ts
new file mode 100644
index 0000000..c9f4fcc
--- /dev/null
+++ b/frontend/src/hooks/useThrottle.ts
@@ -0,0 +1,28 @@
+import React from "react";
+
+// Updates take effect immediately if the last update was more than {interval} ago.
+// Otherwise, updates are throttled to {interval}. The latest value is always sent.
+// The last update always gets executed, with potentially a {interval} delay.
+export function useThrottle(value: string, interval = 500) {
+ const [throttledValue, setThrottledValue] = React.useState(value);
+ const lastUpdated = React.useRef(null);
+
+ React.useEffect(() => {
+ const now = Date.now();
+
+ if (!lastUpdated.current || now >= lastUpdated.current + interval) {
+ lastUpdated.current = now;
+ setThrottledValue(value);
+ } else {
+ const id = window.setTimeout(() => {
+ lastUpdated.current = now;
+ setThrottledValue(value);
+ }, interval);
+
+ return () => window.clearTimeout(id);
+ }
+ }, [value, interval]);
+
+ return throttledValue;
+}
+export default useThrottle;