Skip to content

Add a retry + timeout wrapper with abortable requests to lib/hooks/useFormAction #858

Description

@Baskarayelu

📋 Description

lib/hooks/useFormAction.ts is the shared form-submission hook used across server-action-style forms. Today it does a single fetch(url, { method, body: formData }) inside startTransition and collapses every failure into a static "Network error. Please try again." string. There is no timeout, no abort on unmount, and no retry for transient failures.

This issue hardens the hook with an AbortController-based timeout, cancel-on-unmount, and a bounded retry for idempotent methods, while keeping the existing [state, formAction, isPending] tuple API.

Why this matters: a long-hanging POST currently leaves the form stuck in the pending state forever, and a fast unmount leaks a pending state update — both are real UX and React-warning hazards.

🎯 Requirements & Context

Functional requirements

  • Add a configurable timeoutMs (default e.g. 15000) using AbortController in useFormAction.ts.
  • Abort any in-flight request on unmount and never call setState after unmount.
  • Add bounded retry (default 0; opt-in for safe methods) with backoff for network/5xx.
  • Distinguish timeout vs network vs server error in the returned state.error.

Context & constraints

  • Preserve the exact [state, formAction, isPending] as const return shape — many forms depend on it.
  • Keep ActionState typing from lib/auth/middleware.
  • Stay framework-native (useTransition); do not add a data-fetching dependency.

🛠️ Suggested Execution

git checkout -b feature/use-form-action-retry-timeout
  • Implement abort/timeout/retry; add TSDoc with @example.
  • Add vitest unit tests covering: success, timeout fires abort, unmount cancels (no state update), retry stops after the bound, non-retryable methods never retry.
  • Edge cases: empty body, server returns non-JSON, repeated rapid submits.
npx vitest run
npx tsc --noEmit && npm run lint
feat(hooks): add abortable timeout + bounded retry to useFormAction

✅ Acceptance Criteria & Guidelines

Requirement Target
Public tuple API unchanged Required
Abort-on-unmount + timeout Required
Retry bounded and method-aware Required
Test coverage of new branches ≥ 90%
tsc --noEmit, lint clean Required
Timeframe 96 hours from assignment

💬 Community & Support

Join the RemitWise contributor community on Discord: https://discord.gg/CtQuPZFMA

Please comment to claim the issue and ask questions in the channel. 🚀

Metadata

Metadata

Assignees

No one assigned
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions