Learning ReasonReact Step by Step Part: 9
Tags: reason, react, learning, tutorial
Published: 2019-10-13 17:18:01

---
title: Learning ReasonReact Step by Step Part: 9
published: true
description: Learning how ReasonReact works from a beginner's perspective
tags: reasonml, react, learning, tutorial
series: Learning ReasonReact Step by Step
canonical_url: https://www.rockyourcode.com/learning-reason-react-step-by-step-part-9
---

**UPDATE**:  
ReasonML + BuckleScript is now [Rescript](https://rescript-lang.org/blog/bucklescript-is-rebranding).  
As the ecosystem has changed around those tools, this blog post is not accurate anymore.

---

In the [last post][lastpost], we _finally_ finished the custom `useForm` hook.  
You can see the code on [GitHub][reasonform].

## Use The Custom Hook

Let's switch to our main form component: `scr/Form.re`.

We need to connect the component to our custom hook.

```reasonml
/* src/Form.re */

[@react.component]
let make = (~formType) => {
  let logger = () => Js.log("Form submitted");

  let (state, formRules, handleChange, handleSubmit) =
    UseForm.useForm(~formType, ~callback=logger);

    // JSX here
};
```

So far, so good.

## Display Form Validation Rules

Now let's create a new component called `FormErrors`, which will be in charge of displaying the list of form validation rules and their status.

**☞ [View Demo][demo]**

We'll create a **nested module**. The [Reason Documentation][filestructure] recommends a flat project structure:

> Try not to have too many nested folders. Keep your project flat, and have fewer files (reminder: you can use nested modules).

Inside `src/Form.re`:

```reasonml
let str = ReasonReact.string;

module FormErrors = {
  [@react.component]
  let make = (~formRules: FormTypes.formRules) => // (A)
    <div>
      <ul>
        {
          Array.map(
            rule =>
              <li
                key={rule.FormTypes.id |> string_of_int} // (B)
                className={
                  rule.valid ?
                    "is-success help is-size-6" : "is-danger help is-size-6"
                }>
                <i className={rule.valid ? "fas fa-check" : "fas fa-times"} />
                {" " |> str}
                {rule.FormTypes.message |> str} // (B)
              </li>,
            formRules,
          )
          |> React.array
        }
      </ul>
    </div>;
};
```

The `make` function takes a labeled argument with the type `FormTypes.formRules` (`A`). The `formRules` are defined in `src/FormTypes.re` and we can access them with the dot operator.

We use `Array.map`, a native Reason function, to loop over the Array. Unfortunately, it takes the input function as the first argument the array as the second argument.

Now the type checker doesn't know the type of each `rule`. That's why we have to tell Reason the type _again_ (see lines `B`).

As an alternative, you could use BuckleScript's [Belt library][beltarray], which offers a more familiar syntax for JavaScript developers. `Belt.Array.map` takes the array as a first argument, and the function as the second argument.

We also have to convert types (`B`) and convert the Array to a React.array. Reason's type system is strict, and you have to jump through some hoops to get everything working.

Other than that, the component looks almost the same as a React component.

## Connect Form And FormErrors

We now have to show the `FormErrors` component inside the `Form` component - the same as in normal React.

```reasonml
/* src/Form.re */


[@react.component]
let make = (~formType) => {
  // form logic
 let (state, formRules, handleChange, handleSubmit) = // (A)
    UseForm.useForm(~formType, ~callback=logger);

<div className="section is-fullheight">
    <div className="container">
      <div className="column is-4 is-offset-4">
        <h1 className="is-size-1 has-text-centered is-capitalized">
          {formType |> str}
        </h1>
        <br />
        {
          switch (formRules) {         // (B)
          | [||] => ReasonReact.null
          | _ => <FormErrors formRules />
          }
        }
        <br />
        // more JSX
```

The above code shows how we conditionally display the `FormErrors` component (`B`).

If we don't have any `formRules` we display `ReasonReact.null`: we show nothing.

I'm sure you've previously run into the error that the array is undefined, and the map function can't run.  
We avoid this error by always initializing an array with validation rules. It's either an empty array or an array containing login or registration rules.

If we have an array with rules, display `FormErrors`, and hand down the `formRules` that we received from the custom `useForm` hook (`A`).

## Finished

And that's the complete example. You can find the code on **[Github](https://github.com/sophiabrandt/reason-form)**. I deployed the **[live demo to Firebase][demo]**.

I originally wanted to deploy the demo to GitHub Pages but ran into [client routing problems](https://medium.com/@Dragonza/react-router-problem-with-gh-pages-c93a5e243819).

I'll write a recap and thoughts about my learning process in a later post.

[reasonstep6]: https://www.rockyourcode.com/learning-reason-react-step-by-step-part-6
[demo]: https://reason-form.firebaseapp.com
[reasonform]: https://github.com/sophiabrandt/reason-form/blob/master/src/UseForm.re
[lastpost]: https://www.rockyourcode.com/learning-reason-react-step-by-step-part-8
[filestructure]: https://reasonml.github.io/docs/en/project-structure
[beltarray]: https://bucklescript.github.io/bucklescript/api/Belt.Array.html