Hooks coming to Reason React?


#1

I know this is probably going to be met with what?? It’s not even released in React yet. However, I’m excited about how much this will simplify the interop. Maybe router could become just a premade hook? Maybe reducer as well? I just wanted to talk about the prospects of it.


#2

Looks like Jared had an experiment here: https://github.com/jaredly/hooks-experimental


#3

Not only are hooks great, they seem a great match to the functional languages, so I do hope they land soon.


#4

I think they’re awesome, but it’s funny they’re very side-effect oriented, however they do provide a nice API, much better than classes.


#5

Just like the lifecycle methods :slight_smile:


#6

With Let_anything and bs-epitath (see also) we can have an API as beautiful as with hooks (while keeping the renderprops)

Example:

let component = ReasonReact.statelessComponent("MyComp");
let make = _children => {
    ...component,
    render: (_) => {
        let%Epitath data = render => <DataConsumer render />;
        let%Epitath locale = render => <LocaleSelector render />;
        let%Epitath (name, setName) = render => <StringState defaultValue="maarekj" render />;

        <div> /* use data, locale, name and setName */</div>
    }
};

or even

let component = ReasonReact.statelessComponent("MyComp");
let make = _children => {
    ...component,
    render: (_) => {
        let%Epitath data = withDataConsumer;
        let%Epitath locale = withLocale;
        let%Epitath (name, setName) = withStringState(~defaultValue="maarekj");

        <div> /* use data, locale, name and setName */ </div>
    }
};

#7

Example with WithState

module type Config = {type t;};
module WithStateComp = (Config: Config) => {
  type state = Config.t;
  type action =
    | ChangeValue(state);
  let component = ReasonReact.reducerComponent("StateComp");
  let make = (~render, ~defaultValue: state, _) => {
    ...component,
    initialState: () => defaultValue,
    reducer: (action: action, state: state) =>
      switch (action) {
      | ChangeValue(value) => Update(value)
      },
    render: self =>
      render((self.state, value => self.send(ChangeValue(value)))),
  };
  let withState = (~defaultValue, render) =>
    ReasonReact.element(make(~defaultValue, ~render, [||]));
};

module StringState =
  WithStateComp({
    type t = string;
  });

module IntState =
  WithStateComp({
    type t = int;
  });

module Greeting = {
  let component = ReasonReact.statelessComponent("Greeting");
  let make = _children => {
    ...component,
    render: _ => {
      let%Epitath (value, setValue) = IntState.withState(~defaultValue=0);
      <button onClick={_ => setValue(value + 1)}>
        {ReasonReact.string(string_of_int(value))}
      </button>
    }
  };
};
ReactDOMRe.renderToElementWithId(<Greeting />, "preview");

#8

1 disadvantage of this method I can think of is the tree depth, your API can looks just like hooks adds more levels to your tree with each render props. Performance aside, this makes debugging with react dev tool extremely difficult


#9

Awesome use of Let_anything! Not a bad solution till React Hooks comes out officially.


#10

Feel free to try out BsReact (https://github.com/eldh/bs-react/). It supports hooks and context. (And it has a router hook :slight_smile:)


#11

But will it run Doom support Suspense? :smiley:


#12

Yes, but it doesn’t really make sense to add that without also adding support for code-splitting and React.lazy, which is a slightly bigger task.