A few weeks ago, I started learning ReasonML and ReasonReact.

After doing a basic tutorial, I decided to tackle a form with validation.

Building a simple form is not too hard, but it offers some interesting challenges. Some examples include getting user input and storing it locally, adding validation logic, and displaying the validation messages.

Thus Reason Form was born.

It takes inspiration from James King’s Using Custom React Hooks to Simplify Forms and a (deprecated) course about TDD with React, Flask, and Docker. (The new course is called Authentication with Flask, React, and Docker and uses Formik.)

After some initial hurdles, my main problems stemmed from using React, not ReasonML.

ReasonReact provides a thin wrapper around React. That’s why you have to be familiar with React before you can start with ReasonReact.
The documentation offers an overview but is full of gaps.

For several days, I’ve been wrestling with a nasty bug. My state was out of sync with my render.

After fiddling around with derived state, React Refs, useEffect, and several other forays into StackOverflow and Google, I finally found the solution.

A beginner’s error: mutating state!

ReasonML’s data structures are immutable by default. But optionally, you can opt into mutable updates.

I thought I was smart by using a mutable field that toggled the valid or invalid state of a validation rule.

I coded this with useReducer and a dispatch function and didn’t realize that I modified state directly instead of replacing the state with a new value.

John Otander’s blog post React Hooks and stale state finally made it click.

After switching to an immutable update, everything works fine.