Any UI/logic that performs async work must be resilient to rapid user actions and intermediate async states: prevent re-entry, ensure callbacks use the latest intended state, and avoid losing results/errors when components unmount.
Apply these rules: 1) Guard against re-entry in async handlers
disabled, since Enter/keyboard can bypass button disabling before re-render).const submit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (saving || reloading) return; // prevent duplicate onEnter/rapid submit
setSaving(true);
try {
await onSave(/*...*/);
} finally {
setSaving(false);
}
};
2) Prevent concurrent requests
3) Make timing/streaming callbacks use “latest” state, and verify with tests
4) Be lifecycle-safe for in-flight operations
5) Handle “connecting/pending” phases deterministically
This standard targets the real failure modes described: stale/incorrect final results from scheduled callbacks, duplicated async calls (and conflicting revisions), lost errors due to unmount during pending work, and dropped actions when release happens before the underlying connection is ready.
Enter the URL of a public GitHub repository