Lessons learned and notes from my first ReasonML/ReasonReact app
Tags: reason, reasonreact, javascript, webdev
Published: 2020-03-11 13:16:31

I recently released a side project, [RSync Command Generator](https://rsync.snipline.io). This is a simple GUI for generating `rsync` commands for the command line.

![Preview of the Rsync Command Generator](https://res.cloudinary.com/snipline/image/upload/v1583931806/preview-v2_ntrdzu.png)

I’ve been casually learning ReasonML for a while and thought this would be a great project to try it out on. My main goal for ReasonML is to create native apps with ReveryUI, however, I thought I’d give ReasonReact a try first as there’s more resources out there. So here’s my initial thoughts, impressions, and tips to new comers.

## Not knowing React is a disadvantage

I’ve used React once about 4 years ago. 

I mostly stick with VueJS, EmberJS, or StimulusJS. These 3 frameworks have covered most of my use-cases. I would love it if I could use any of these frameworks with ReasonML. Unfortunately, I’m not confident enough in my ReasonML knowledge to make my own bindings so ReasonReact or  Bucklescript-TEA are my options.

The ReasonReact docs are fairly good to get started but they do require base knowledge of React. I had to go and learn about hooks and reducers from various React tutorials. I’m still not sure how to use `useEffect` but hey, I know it exists.

Even without this understanding of `useEffect`, this has not stopped me from creating an app in ReasonReact. There are plenty of resources out there that can be used to get going.

One of which is the react-hooks starter template for ReasonReact. This has some great examples which I referred to many times.

If you’re building an SPA, I’d recommend checking these for a reference but using `spin` (see below) for the actual project structure.

## What I Like about ReasonML

* Inferred types.
* Changing state with actions.
* Immutability.
* Being able to fall back to JS when needed.
* Fast compilation and decent compiler feedback.
* The syntax (With some minor exceptions).

```reasonml
// A small glimpse into the structure
type state = {
	preferShortFlags: bool,
};

type action =
	| TogglePreferShortFlags;

let initialState = {
	preferShortFlags: false
};

let reducer = (state, action) => {
  switch (action) {
  | TogglePreferShortFlags => {...state, preferShortFlags: !state.preferShortFlags}
  };
};

[@react.component]
let make = () => {
  let (state, dispatch) = React.useReducer(reducer, initialState);

  <Container>
	<Header/>
    /* ... */
  </Container>;
};
```

## What I Dont' Like

* Some parts of the language are annoying. Having to use `type_` instead of `type` often caught me out. Raw JS syntax is a bit strange as well.
* Having to use `className` instead of `class` - a similar bane to `type_` although I think this is a JS issue rather than because of a Reason keyword.
* The documentation is good but I need more of it!

My initial reaction to some of the syntax was a subconscious "nope". Things like `+.` for adding floats. These quirks of the language have started to grow on me, though. I think learning more about OCaml, what ReasonML transpiles to, has helped me appreciate these things more.

## Reaching for Javascript When You Need To

I only reached for native JS once and that was to copy to clipboard. There is at least one BuckleScript library for this but I could not get it working. The JS ended up looking like this (Not my finest code).

```reasonml
	let copy = (dispatch, showEvent, hideEvent) => {
		let copyJs = [%bs.raw 
			{| 
			function(text, showEvent, hideEvent) {
			if (window.clipboardData && window.clipboardData.setData) {
				dispatch(showEvent);
				window.setTimeout(function() { dispatch(hideEvent)}, 1500);
				return clipboardData.setData("Text", text); 

			} 
			else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
				var textarea = document.createElement("textarea");
				textarea.textContent = text;
				textarea.style.position = "fixed";
				document.body.appendChild(textarea);
				textarea.select();
				try {
					dispatch(showEvent);
					window.setTimeout(function() {dispatch(hideEvent)}, 1500);
					return document.execCommand("copy");
				} catch (ex) {
					console.warn("Copy to clipboard failed.", ex);
					return false;
				} finally {
					document.body.removeChild(textarea);
				}
			}
			}
		|}
		];
		copyJs(command, showEvent, hideEvent);
	};
```

It can then be called like this

```reasonml
<button role="button" ariaLabel="Copy to Clipboard" onClick={_event => copy(dispatch, DisplayNotice, HideNotice)} className="ml-4">
/* ... */
</button>
```

With this code I passed in actions so that I could toggle showing feedback to the user. It's a bit hacky, but hey, it works!

![Copying to clipboard](https://f002.backblazeb2.com/file/snipline/Screenshot%202020-03-06%20at%2014.55.46.png)

## Deployment with Zeit Now

I deployed the project with [Zeit Now](https://zeit.co). One thing I noticed was that non-root URLs don’t work out of the box. It’s pretty simple to configure them to work with a `now.json` file.

```json
{
	  "routes": [
			{ "src": "/", "dest": "/index.html" },
			{ "src": "/common", "dest": "/index.html" }
		]
}
```

For dynamic URLs [check the documentation](https://zeit.co/docs/configuration#project/routes).

## Useful links

The [Reason React Documentation Examples](https://reasonml.github.io/reason-react/docs/en/simple) are great for understanding how to communicate between components and using state.

[Rock Your Code](https://www.rockyourcode.com/learning-reason-react-step-by-step-part-0/) ([@hisophiabrandt](https://twitter.com/hisophiabrandt)) has a great series on ReasonReact which I very much enjoyed reading through. Includes some great external resources, too.

[spin](https://github.com/tmattio/spin) - Project scaffolding tool. I wish I knew about this from the start. It has an excellent starter template for ReasonReact which includes Router setup and an option for using TailwindCSS.

[Reason React Hacker News](https://github.com/reasonml-community/reason-react-hacker-news) - Great project for referencing how to do things.

[Real World OCaml](https://dev.realworldocaml.org/) - Great for giving  context to how ReasonML works.

[Web Development with ReasonML](https://pragprog.com/book/reasonml/web-development-with-reasonml)

## Would I use it again?

Absolutely. Overall, I really like ReasonML, and I hope its popularity grows. 

I think for now I will continue to use this for smaller projects while I get to grips with it. Hopefully I’ll get confident enough to release a native ReveryUI app in the near future.