Experiment/Best practice? How to use hooks created in ReasonML in JS react app?


#1

Since both React and ReasonReact are based on hooks, I thought this could be a natural integration point. In this case, I could write or rewrite my API (fetching) in Reason, and expose the data to React through hooks written in Reason. Do you think this is a good idea?

Looking at this example in GitHub (big shoutout to jihchi/reason-react-realworld-example-app) with the relevant files being: API.re, Hook.re, and Shape.re. The hooks call the API, which in turn uses Shape.re to decode the JSON.

However, I think this may take some work to get fully interoperable and I’m not sure if the types defined in Shape.re could be used from JS directly or if some translation is necessary.

Motivation: we can’t rewrite our ReactJS components right now, but this may be a way to initiate a gradual conversion.


#2

If I understand correctly, you’re asking about how to call Reason from Javascript. I’m not sure if there is a community stance on what one should do. However, I have written code in Reason and used it in Javascript without much ceremony.

Essentially, you just need to undestand how certain datatypes map to the generated javascript code. The basics map very cleanly.

  • Booleans are just booleans.
  • Ints and Floats get turned into numbers.
  • Optionals are stripped, and the None case is represented by undefined.
  • If you need null, then you have to use Js.Nullable.t
  • Records and Js.Dict.t get turned into objects (assuming you’re on the latest bucklescript… otherwise you’ll have to deal with bs.abstract… see the docs)
  • Arrays get turned into javascript arrays.

The parts where things get a little tricky is with lists and variants. You might have to export convenience functions for constructing such values. This is where I’m still a bit hazy, and actually, I would be glad if some other community members chimed in and verified whether this solution is valid.

For variants, I am just creating a module with values for each of the constructors. For example:

Foobar.re

type t = [
  | `Foo(int)
  | `Bar(t)
];

module Js = {
  let foo: int => t = x => `Foo(x);
  let bar: t => t = x => `Bar(x);
};

Then we are accessing them in javascript as such:

import * as Foobar from "./Foobar.bs";

const foo = Foobar.Js.foo(1);
const bar = Foobar.Js.bar(foo);

This method should also be compatible with hooks, since hooks are implemented as normal functions. I guess the tricky bit is going to be the cases where your hooks return a variant. If that’s the case, then you’re probably going to have to add more functions in your Js module to help you match on the various cases.

I know it’s not great, but as I said, perhaps there’s a better solution the community knows about that I don’t. Hopefully others could chime in?