How to constraint a child with particular component?

reasonreact

#1

Hi all

I created a following component:

let component = ReasonReact.statelessComponent("NavLinkView");

let make = (~text: string, ~href: string, _children) => {
  ...component,
  render: (_self) => {
    <li className="nav-item">
      <a className="nav-link" href={href}>
        <i className="fa fa-fw fa-dashboard"></i>
        <span className="nav-link-text">{ReasonReact.string(text)}</span>
      </a>
    </li>
  }
};

then this component should be a child of the following component:

let component = ReasonReact.statelessComponent("NavItemView");

let make = (children: NavLinkView) => {
  ...component,
  render: _self => {
    <div className="nav-item">
    </div>
  }
};  

I want to constraint, that the component NavItemViewonly accepts the component NavLinkView . Is it possible?

Thanks


#2

You can’t currently, because all component are of the same ReasonReact.reactElement type. You can definitely constrain it to be a string, int, or whatever other types.


#3

Dang, I was wondering this same thing. I was hoping to implement something like Elm’s style-elements but I guess this isn’t possible :confused:. Is there plans to do this in the near future? I kind of wish the JSX syntax for react was less prescriptive. I wouldn’t even mind having to have the functions in scope for divs and such if needed (it could just be a open away). However I guess the difference lies in the fact that ReasonReact’s components do a lot more side effects than Elm’s simple system does.


#4

You might be able to answer this quickly, but can you bind instanceOf via BS, then use it to determine the component? You might not able able to get the compiler to catch it, but you could throw warnings/errors in to the console.


#5

Not a bad idea :thinking:. I was actually thinking of maybe wrapping the subcomponent in a opaque type then having the inner component unwrap it before render… I’ll have to try it.


#6

Try it:

module type NavLinkViewInterface = {
  type element;
  let create: (~text: string, ~href: string) => element;
  let unwrap: element => ReasonReact.reactElement;
};

module NavLinkView: NavLinkViewInterface = {
  let component = ReasonReact.statelessComponent("NavLinkView");
  type element = ReasonReact.reactElement;
  let make = (~text: string, ~href: string, _children) => {
    ...component,
    render: _self =>
      <li className="nav-item">
        <a className="nav-link" href>
          <i className="fa fa-fw fa-dashboard" />
          <span className="nav-link-text">
            (ReasonReact.stringToElement(text))
          </span>
        </a>
      </li>,
  };
  let create = (~text: string, ~href: string) =>
    ReasonReact.element(make(~text, ~href, [||]));
  let unwrap = element => element;
};

module NavItemView = {
  let component = ReasonReact.statelessComponent("NavItemView");
  let make = (children: NavLinkView.element) => {
    ...component,
    render: _self =>
      <div className="nav-item"> (NavLinkView.unwrap(children)) </div>,
  };
};

ReactDOMRe.renderToElementWithId(
  <NavItemView>
    ...(NavLinkView.create(~text="link", ~href="https://www.google.com"))
  </NavItemView>,
  "preview",
);


#7

Looks pretty good! The only thing I really wish was that you could still use JSX, with this method it’s not possible right?