TypeError: Cannot call a class as a function


#1

hey folks. I have this binding:

// ReactRouterDom.re
module Link = {
  [@bs.obj]
  external makeProps:
    (~to_: string, ~children: React.element, ~key: string=?, unit) =>
    {
      .
      "to": string,
      "children": React.element,
    } =
    "";
  [@bs.module "react-router-dom"]
  external make:
    {
      .
      "to": string,
      "children": React.element,
    } =>
    React.element =
    "Link";
    [@genType]
    let default = make;
};

that i am using here:

module Link = ReactRouterDom.Link;

[@react.component]
let make = () => {
  <div>
    <h1> {"404 Page Not Found" |> React.string} </h1>
    <p> {"Please check the URL and try again" |> React.string} </p>
    <Link to_="/home">
      {"Click here to return to the homepage" |> React.string}
    </Link>
  </div>;
};

React.setDisplayName(make, "NotFoundPage");
[@genType]
let default = make;

this compiles.
i am importing the file into js

import NotFoundPage from "./components/NotFoundPage.gen.js";

when i go to some random page i get this error TypeError: Cannot call a class as a function

This is what it looked like in Jsx2


module LinkOld = {
  [@bs.module "react-router-dom"]
  external linkClass: ReasonReact.reactClass = "Link";

  let make =
      (
        ~to_: string,
        children,
      ) => {
    /* So far we keep this for Link prop compatibility reasons */
    let _dontuse = activeClassName;
    let props = {"to": to_};
    ReasonReact.wrapJsForReason(~reactClass=linkClass, ~props, children);
  };
};

Any ideas? Thank you in advance.


#2

@idkjs Could you also post the compiled ReactRouterDom.bs.js JS file?

I suspect that the type here is wrong - when binding to a class component on the JS side, I’m using the React.component('a) type:

  [@bs.module "react-router-dom"]
  external make: React.component({. "to": string, "children": React.element }) = "Link";

#3

ReactRouterDom.gen

/* Untyped file generated by genType. */

import * as ReactRouterDomBS from './ReactRouterDom.bs';

export const $$default = ReactRouterDomBS.Link[0];

export default $$default;

export const $$default = ReactRouterDomBS.Link2[0];

export default $$default;

ReactRouterDom.bs.js

// Generated by BUCKLESCRIPT VERSION 5.0.6, PLEASE EDIT WITH CARE

import * as ReasonReact from "reason-react/src/ReasonReact.js";
import * as ReactRouterDom from "react-router-dom";
import * as Js_null_undefined from "bs-platform/lib/es6/js_null_undefined.js";

function make(to_, className, activeClassName, children) {
  var props = {
    to: to_,
    className: Js_null_undefined.fromOption(className)
  };
  return ReasonReact.wrapJsForReason(ReactRouterDom.Link, props, children);
}

var LinkOld = /* module */[/* make */make];

function $$default(prim) {
  return ReactRouterDom.Link(prim);
}

var Link = /* module */[/* default */$$default];

var $$default$1 = ReactRouterDom.Link;

var Link2 = /* module */[/* default */$$default$1];

export {
  LinkOld ,
  Link ,
  Link2 ,
  
}
/* default Not a pure module */


#4

Looks like the code created by the Link.make binding tries to call ReactRouterDom.Link component as a function, which results in your reported error (probably because it’s a class component).

function $$default(prim) {
  return ReactRouterDom.Link(prim);
}

Changing the Link.make binding type to React.component should help. ReactRouterDom.Link needs to be treated as a component, not a function:

[@bs.module "react-router-dom"]
external make: React.component({. "to": string, "children": React.element }) = "Link";

#5

@pewniak747 thank you sir. I am going to try it out an get back.