--- description: Prevent double-click / duplicate API calls from frontend UI alwaysApply: true --- # Prevent duplicated API calls (frontend) When wiring UI actions (buttons, row actions, dialogs) to backend APIs, **always prevent double submission**. Relying on `setState` + `disabled` alone is not sufficient because rapid double-click can fire twice before React re-renders. - **Must**: add an **in-flight lock** (e.g. `useRef(false)`) and early-return if already running. - **Must**: keep the UI disabled/loading (`disabled={isLoading}`) for user feedback. - **Must**: clear the lock in `finally` so it always releases. - **Should**: if the same endpoint can be triggered from multiple places, consider a shared “single-flight” helper (dedupe by `method+url+body` key). Example pattern: ```tsx const inFlightRef = useRef(false); const [isSaving, setIsSaving] = useState(false); const onSave = async () => { if (inFlightRef.current) return; inFlightRef.current = true; setIsSaving(true); try { await doRequest(); } finally { setIsSaving(false); inFlightRef.current = false; } }; ```