Converting JS to ReasonML with Bindings — Part 3

Importing Header.re to Layout.js Component

Alain
5 min readFeb 9, 2019

The rest of the Converting JS to ReasonML with Bindings Series can be found here: Part 1, Part 2, Part 3, Part 4.

Where Do We Start

If we take a look at the imports on layout.js we see a few things we need to handle.

So we need to a StaticQuery, Header, Helmet and to import some css.

Header

Let’s start with creating the reason version of Header.re.

Create Header.re in the components directory.

These are functions we need to convert.

We already got the Link from our our reason-gatsby-link import so we dont have to work about that.

The last three we will create using bucklescript like we did before.

The `navigate` biniding

For navigate from @reach/router we don't even have to look anything up. We know there is an export called navigate on the @reach/router module. So let try talking through the binding out loud.

bucklescript get module @reach/router and access it with a function callednavigate that takes a string. When you get the string, call the function on the @reach/router navigate function. unit is the keyword that calls the function for us.

And this is what it looks like in code:

The `auth.js` binding

The auth.js file is a module like any other. Instead of importing it, you wrote it yourself. So we call it the exact same way. Talking through it out loud,

bucklescript get the module auth at ../utils/auth path and access it with a function called logout that takes any old type 'a. When you get the 'a thingy, call the function on the ../utils/auth module with the name logout. I'm giving you the 'a type because this function takes a call back and I actually don't know how to type that correctly just yet so just take any old thing until i figure it out.

The `isLoggedIn` binding

Talking to ourselve out loud again:

For isLoggedIn create a function called isLoggedIn which expects to get a boolean type back. Everytime I call it, immediately hit isLoggedIn at ../utils/auth which should return a true or false.

This is the code version of those two statements:

This is the logout function in auth.js:

We see that it takes a callback so I know that I have to pass it one. I am not sure how to type it which is why I used the 'a type annotation which basically means take anything at all.

In Header.js logout was called like this:

Reading this, I see that first we are calling signOut on the Amplify module. Just to mirror the Header.js file so you could see what is going on, I ripped it from Amplify.re and redefined it here. Later we will just call it from there.

So, we are calling signOut then logging the user out by clearing out the local store on the local machine. If that works, call navigate to take the person back to the app/login page and log any errors.

To do this, I had to go find some code I read somewhere on git hub showing how to do a js style try/catch statement. I haven’t seen that documented anywhere so that is a great example of why reading other people’s code helps you solve problems. I saw how it was used here and came up with this:

Which I passed to the onClick function here:

This is a ternary function which first checks if the user is logged in or out. If the user, is logged in, then show the dom element with the signout button on it. If not, don’t show it. That is the ReasonReact.null part. You could have used just <div />.

In the onClick key, the value is set to a function that listens for the click _event which we preceed with an underscore to let the compiler know that we won't be using the event, we just want to know that it happened. Then when it happened, call our signOut function. Note the signature:

We defined it as taking the amplify type and then calling unit. Here it is again.

[@bs.send] external signOut: (amplify, unit) => unit = "signOut";

It doesn't take any params. Just tells Amplify to sign out anyone who is signed in right now. Then we go to sign the person out on this machine. Our sign in code, which we have not discussed yet, saves a token to local storage. Apparently, when we call logout fromauth.js we are deleting the token. We almost don't have to care. We just give the function what it wants and let it go to work. In this case, it wants a call back to check for errors…

Sidenote: I went to go get you the api for Js.Exn and ran into the documentation for the Js style try on the bucklescript docs. That, my friends, is how you build the knowledge. I am not even going to write this post pretending I knew that. Here it is, we have learned it at the same time.

So the callback calls navigate and lets gives any Js erros using the Js.Exn.Error module from bucklescript. Thanks, @bobzhang1988.

So know we are calling auth.js from our reason file which is calling back out to javascript files. Interop Madness people. You are not ready!!!

Here is what the working code looks like:

Go back into src/layout.js and replace the Header import. Change:

to:

import Header from './Header.bs'

Run gatsby develop to refresh if it didn't. Rejoice!

Show me the code. See tag creating-layout-component-header-import.

Incidentally, as most of you know, there are plenty of ways to do this. I am just doing piecemeal so you can see how easy it is without making huge changes. By the end we will have refactored to get the full power of ReasonML.

I was going to try to re-create Helmet.js in Reason just to systematically go through this with you all but it got a bit convoluted. I went to get some help on the discord which I want to invite you to join, and decide not to do it after talking to some of the folks on there.

Getting and Giving Help

Important point on community help and mental health. I have rules to keep my spirit up when I get frustrated. In relevant part, if you haven't asked someone the question, you are the @$$hole in the room. So go to www.stackoverflow.com or www.reason.chat or Reason's Discord channel and ask the damned question. If it's an important problem, get the answer on stackoverflow or reason.chat because it will be easier to find later. I don't know how many times I have looked something up and come up on my own previous question or even answer to someone and found the answer while doing an internet or github search. Sharing helps everyone.

--

--

Alain

Interests include Living Free, Biz, Tech and employment (https://fr.linkedin.com/in/alainarmand) Blindly stumbling towards fullstack competency. I ❤ Open Source