react-docgen icon indicating copy to clipboard operation
react-docgen copied to clipboard

No suitable component definition found for container component

Open m860 opened this issue 6 years ago • 9 comments

type Props = {
    children: React.Element,
    renderStatus?: () => React.Element
};
function Test(props: Props, context) {
    if (context.show) {
        return props.renderStatus ? props.renderStatus() : null;
    }
    return props.children;
}

Test.contextTypes = {
    show: PropTypes.bool
};
export default React.memo(Test)

output

 Error: No suitable component definition found.

m860 avatar Mar 15 '19 07:03 m860

That's because Test doesn't pass the heuristic used to determine whether a function is a React component or not. A quick workaround would be to use

return <>{props.children}</>;

@danez, any thoughts on extending the heuristic? Test.contextType is a give-away, but it may not always exist. Should we actually add support for marking functions as react components via a tag (i.e. @react or something), to have a simple escape hatch?

fkling avatar Mar 19 '19 22:03 fkling

There are two problems in this example:

  1. React.memo() was not supported, will be fixed in #343
  2. The component does not return jsx as felix mentioned and is therefore not detected as component.

I think adding support for @react is a good last resort. I will try to add propTypes, defaultProps and contextTypes to the detection first.

danez avatar Apr 13 '19 22:04 danez

Similar issue when returning a portal.

Simplified example:

const Dialog = (props) => {
  return ReactDOM.createPortal(<MyDialogHere {...props}/>, document.body);
}


Dialog.propTypes = {
  /** If only these docs could be detected... */
  children: PropTypes.node
}

The fragment workaround does work, but +1 for allowing the presence of propTypes to trigger detection like @danez mentioned.

greypants avatar May 30 '19 01:05 greypants

I'm experiencing the same when returning a portal. Interestingly enough, it works when using a class component instead.

cironunes avatar May 30 '19 03:05 cironunes

Also ran into this problem with a functional component which returns ReactDOM.createPortal(...). It would be nice to not have to wrap in a fragment.

robertwbradford avatar Aug 08 '19 16:08 robertwbradford

Similar issue when returning a portal.

Simplified example:

const Dialog = (props) => {
  return ReactDOM.createPortal(<MyDialogHere {...props}/>, document.body);
}


Dialog.propTypes = {
  /** If only these docs could be detected... */
  children: PropTypes.node
}

The fragment workaround does work, but +1 for allowing the presence of propTypes to trigger detection like @danez mentioned.

I use the fragment workaround but with shorthand fragment <></> does not work only with explicit <React.Fragment> or any other html wrapper like <div>

dastasoft avatar Oct 30 '19 12:10 dastasoft

Useful for "container" like components, similar to the downshift API.

import * as React from 'react'

type Props = {
  render: () => React.Element<any>,
}

function MyComponent({ render }: Props) {
  return render()
}

export default MyComponent;

I understand that with such case there's not much to rely on to distinguish a component from a function. Maybe the fact that react is imported?

pascalduez avatar Dec 30 '19 16:12 pascalduez

Inside functional component, if createPortal() method is used, be sure NOT to return null in the ternary operator.

Instead of this,

return opened ? ReactDOM.createPortal(renderHTML(), document.body) : null;

use this,

return opened ? ReactDOM.createPortal(renderHTML(), document.body) : <></>;

This solved my problem. :)

av1v3k avatar Apr 15 '21 13:04 av1v3k

To add to the discussion, aside from ReactDOM.createPortal, you can reproduce this bug with other "wrapper" functions as well (using version 5.4.3):

import { Popup } from '/path/to/example/Popup';
let container = <div>Foo Bar</div>;
return Popup.attach(container, 'Hello World'); // Error: No suitable component definition found.

^ Fragment workaround works here too. e.g. return <>{Popup.attach(container, 'Hello World')}</>

neutraali avatar Nov 15 '22 15:11 neutraali