React-joyride: Providing class component to tooltipComponent yields 'cannot call class as function' error

Created on 2 Aug 2018  路  2Comments  路  Source: gilbarbara/react-joyride

Expected behavior
When providing a reference to a class component to tooltipComponent (for a steps props, it will render without error.

Actual behavior
When providing a class component (rather than an element), it errors out with cannot call class as a function.

Steps to reproduce the problem
Create a class component a la class CustomTooltip extends React.Component {...}. Pass a reference the class you just created to the tooltipComponent prop of the step.

React version
16.2.0

React-Joyride version
^2.0.0-13

Browser name and version
Chrome 67.0

Error stack (if available)
Tooltip.jsx?2cfc:5 Uncaught TypeError: Cannot call a class as a function
at _classCallCheck (Tooltip.jsx?2cfc:5)
at Tooltip (Tooltip.jsx?2cfc:23)
at JoyrideTooltip.render (index.js?3c59:1721)
at finishClassComponent (react-dom.development.js?f8c1:7873)
at updateClassComponent (react-dom.development.js?f8c1:7850)
at beginWork (react-dom.development.js?f8c1:8225)
at performUnitOfWork (react-dom.development.js?f8c1:10224)
at workLoop (react-dom.development.js?f8c1:10288)
at HTMLUnknownElement.callCallback (react-dom.development.js?f8c1:542)
at Object.invokeGuardedCallbackDev (react-dom.development.js?f8c1:581)
_classCallCheck @ Tooltip.jsx?2cfc:5
Tooltip @ Tooltip.jsx?2cfc:23
render @ index.js?3c59:1721
finishClassComponent @ react-dom.development.js?f8c1:7873
updateClassComponent @ react-dom.development.js?f8c1:7850
beginWork @ react-dom.development.js?f8c1:8225
performUnitOfWork @ react-dom.development.js?f8c1:10224
workLoop @ react-dom.development.js?f8c1:10288
callCallback @ react-dom.development.js?f8c1:542
invokeGuardedCallbackDev @ react-dom.development.js?f8c1:581
invokeGuardedCallback @ react-dom.development.js?f8c1:438
renderRoot @ react-dom.development.js?f8c1:10366
performWorkOnRoot @ react-dom.development.js?f8c1:11014
performWork @ react-dom.development.js?f8c1:10967
requestWork @ react-dom.development.js?f8c1:10878
scheduleWorkImpl @ react-dom.development.js?f8c1:10732
scheduleWork @ react-dom.development.js?f8c1:10689
scheduleTopLevelUpdate @ react-dom.development.js?f8c1:11193
updateContainer @ react-dom.development.js?f8c1:11231
(anonymous) @ react-dom.development.js?f8c1:15226
unbatchedUpdates @ react-dom.development.js?f8c1:11102
renderSubtreeIntoContainer @ react-dom.development.js?f8c1:15225
render @ react-dom.development.js?f8c1:15290
(anonymous) @ index.jsx?0ed3:470
setTimeout (async)
(anonymous) @ index.jsx?0ed3:409

If you want to get this issue fixed quickly, make sure to send a public URL or codesandbox example.
No codesandbox since repro steps should cover it conceptually.

*bonus round -- some digging
Pretty sure that the block in question (in react-joyride source) is

if (tooltipComponent) {
        var renderProps = _extends({}, buttonProps, {
          content: content,
          continuous: continuous,
          index: index,
          isLastStep: isLastStep,
          locale: locale,
          setTooltipRef: setTooltipRef,
          size: size,
          title: title
        });

        if (React.isValidElement(tooltipComponent)) {
          component = React.cloneElement(tooltipComponent, renderProps);
        } else {
          component = tooltipComponent(renderProps);
        }
      }

specifically, the component = tooltipComponent(renderProps); line. It seems like as a workaround you can provide an element like to customTooltip, but it seems strange that you'd have to do that. I'm wondering if we can add in a check to see if something is a class component, and then perhaps do something like component = <TooltipComponent ...props />. If there's a specific reason why not to do that, I'd also be curious to hear that too. Thank you!

V2 bug urgent

Most helpful comment

I noticed this potential issue when looking at the source on a different occasion. I didn't need a class component myself, but this issue reveals it is indeed a problem.

@gilbarbara, Repros are often nice, but this issue seems pretty straightfoward. @man-of-seafood is defining a class component, and passing it to joyride like <Joyride tooltipComponent={MyClassComponent} />, and it's erroring.

As mentioned above, this source seems to be the culprit:

https://github.com/gilbarbara/react-joyride/blob/f69dec61b1d87827cfe8ae4a1f3b3878c4c59c4a/src/components/Tooltip/index.js#L81-L86

Line 85 assumes the provided component is a function. Can the following be used instead?

else {
  const TooltipComponent = tooltipComponent;
  component = <TooltipComponent {...renderProps} />;
}

It will still work the same for any function accepting props as a single argument, but also works for class components.

All 2 comments

I need a working example.

I noticed this potential issue when looking at the source on a different occasion. I didn't need a class component myself, but this issue reveals it is indeed a problem.

@gilbarbara, Repros are often nice, but this issue seems pretty straightfoward. @man-of-seafood is defining a class component, and passing it to joyride like <Joyride tooltipComponent={MyClassComponent} />, and it's erroring.

As mentioned above, this source seems to be the culprit:

https://github.com/gilbarbara/react-joyride/blob/f69dec61b1d87827cfe8ae4a1f3b3878c4c59c4a/src/components/Tooltip/index.js#L81-L86

Line 85 assumes the provided component is a function. Can the following be used instead?

else {
  const TooltipComponent = tooltipComponent;
  component = <TooltipComponent {...renderProps} />;
}

It will still work the same for any function accepting props as a single argument, but also works for class components.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sarates picture sarates  路  6Comments

shri3k picture shri3k  路  5Comments

monsieurnebo picture monsieurnebo  路  4Comments

pokonski picture pokonski  路  3Comments

SamSunani picture SamSunani  路  4Comments