Loading...
Please waitLoading...
Please waitPrevent double submissions by locking form submissions. Common solution for preventing duplicate form submissions.
pnpm dlx uselab@latest add use-submit-lock
import * as React from "react"
import { useSubmitLock } from "@/hooks/use-submit-lock"
function ContactForm() {
const { locked, lock, unlock } = useSubmitLock()
const [formData, setFormData] = React.useState({ email: "", message: "" })
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (locked) return
lock()
try {
await submitForm(formData)
} finally {
unlock()
}
}
return (
<form onSubmit={handleSubmit}>
<input
value={formData.email}
onChange={(e) =>
setFormData((prev) => ({ ...prev, email: e.target.value }))
}
disabled={locked}
/>
<button type="submit" disabled={locked}>
{locked ? "Submitting..." : "Submit"}
</button>
</form>
)
}useSubmitLock(options?)| Name | Type | Description | Default |
|---|---|---|---|
initialLocked | boolean | Whether the lock should be initially locked. | false |
autoUnlockDelay | number | Automatically unlock after this many milliseconds (0 = disabled). | undefined |
| Name | Type | Description |
|---|---|---|
locked | boolean | Whether the form is currently locked. |
lock | () => void | Lock the form to prevent submissions. |
unlock | () => void | Unlock the form to allow submissions. |
toggle | () => void | Toggle the lock state. |
function LoginForm() {
const { locked, lock, unlock } = useSubmitLock()
const [email, setEmail] = React.useState("")
const [password, setPassword] = React.useState("")
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (locked) return
lock()
try {
await login(email, password)
} catch (error) {
console.error("Login failed:", error)
} finally {
unlock()
}
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
disabled={locked}
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={locked}
/>
<button type="submit" disabled={locked}>
{locked ? "Logging in..." : "Login"}
</button>
</form>
)
}function PaymentForm() {
const { locked, lock } = useSubmitLock({
autoUnlockDelay: 5000, // Auto-unlock after 5 seconds
})
const handlePayment = async () => {
if (locked) return
lock()
try {
await processPayment()
} catch (error) {
console.error("Payment failed:", error)
}
// No need to manually unlock - it will auto-unlock after 5 seconds
}
return (
<button onClick={handlePayment} disabled={locked}>
{locked ? "Processing..." : "Pay Now"}
</button>
)
}function AdminPanel() {
const { locked, lock, unlock, toggle } = useSubmitLock({
initialLocked: false,
})
return (
<div>
<button onClick={lock}>Lock Submissions</button>
<button onClick={unlock}>Unlock Submissions</button>
<button onClick={toggle}>Toggle Lock</button>
<p>Status: {locked ? "Locked" : "Unlocked"}</p>
</div>
)
}function DataForm() {
const { locked, lock, unlock } = useSubmitLock()
const [error, setError] = React.useState<string | null>(null)
const handleSubmit = async (data: FormData) => {
if (locked) return
lock()
setError(null)
try {
await submitData(data)
} catch (err) {
setError(err instanceof Error ? err.message : "Submission failed")
unlock() // Unlock on error so user can retry
} finally {
// Only unlock if no error (success case)
if (!error) {
unlock()
}
}
}
return (
<form onSubmit={handleSubmit}>
{error && <div className="error">{error}</div>}
<button type="submit" disabled={locked}>
{locked ? "Submitting..." : "Submit"}
</button>
</form>
)
}unlock() in a finally block to ensure the lock is released even if an error occurs.autoUnlockDelay for automatic unlock after a timeout, useful for preventing indefinite locks.locked state can be used to disable form inputs and buttons during submission.toggle method is useful for manual lock control in admin panels or debug interfaces.