React forms rarely fail because the input element is difficult. They fail when several parts of the product make a decision at the same time: validation says one thing, the network request says another, and the UI still has an old error on screen.
I have found a useful fix in both JavaScript and TypeScript projects: give the form one typed decision boundary. The component should receive one state, decide what the user can do next, and leave network effects to a separate layer. This makes a feature feel faster because it is more predictable, even when the server is not.
The real problem is an unowned decision
The usual starting point looks harmless:
const [ isLoading , setIsLoading ] = useState ( false ) ; const [ hasError , setHasError ] = useState ( false ) ; const [ isComplete , setIsComplete ] = useState ( false ) ;
Enter fullscreen mode
Exit fullscreen mode
After a few product requests, these booleans can describe states that should never exist. Is a completed form still loading?…