Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No suitable component definition found #37

Closed
panayi opened this issue Nov 14, 2015 · 27 comments
Closed

No suitable component definition found #37

panayi opened this issue Nov 14, 2015 · 27 comments

Comments

@panayi
Copy link
Contributor

panayi commented Nov 14, 2015

image

I know this is not an issue specifically with react-styleguidist, for example: reactjs/react-docgen#29

This happens in a lot of cases: when extending/composing components, or when using Redux and the connect() wrapper. For example, the following component is not recognised:

class Theme extends Component {
  // ...
  render() {
    // ...
  }
}

function mapStateToProps(state) {
  const variables = selectVariables(state.theme.name)
  return {
    variables: selectVariables(state.theme.name),
    styles: selectStyles(state.theme.name, variables)
  }
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators(ThemeActions, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(Theme)

When using wrappers, we could use two files: _Theme.jsx (export "raw" component and use it for styleguide), and Theme (that uses wrappers etc.). However it would be great if it just work.

Any ideas on what needs to be done?

@sapegin
Copy link
Member

sapegin commented Nov 14, 2015

Any ideas on what needs to be done?

That’s what I wanted to ask you :-| No ideas right now.

@mik01aj
Copy link
Collaborator

mik01aj commented Nov 17, 2015

Maybe the update of react-docgen will fix this.

If not, I believe this bug should be reported to react-docgen, as it is thrown from https://github.com/reactjs/react-docgen/blob/c94b7689484be5fb5b573d24d4d7c04833d03fd8/src/parse.js

@panayi
Copy link
Contributor Author

panayi commented Nov 17, 2015

I have worked a bit on this, and react-docgen will search for a "suitable" component definition in any of the exports. So,

Before:

// this throws the above error
module.exports = someWrappedComponent

After:

// react-docgen will find a component in module.exports.otherKey and use that.
module.exports = {
  default: someWrappedComponent,
  otherKey: suitableComponent
}

However when doing the latter react-styleguidist fails since it expects that a single default component is exported, see https://github.com/sapegin/react-styleguidist/blob/master/loaders/styleguide.loader.js#L26.

I think react-styleguidist should use whatever component react-docgen resolves to.

@sapegin
Copy link
Member

sapegin commented Nov 30, 2015

react-docgen do not export any information about the component object. I think we can add a custom resolver function to the config. Like this:

resolveComponent = function(filepath) {
    return 'require(' + JSON.stringify(filepath) + ').otherKey';
}

Any better ideas?

@panayi
Copy link
Contributor Author

panayi commented Nov 30, 2015

However it exports the resolver. I think something similar to this could work:

import recast from 'recast'
import { parse, resolve } from 'react-docgen'

export default function getComponentForStyleGuide(src) {
  var ast = recast.parse(src, {esprima: babylon});
  return resolver(ast.program, recast);
}

@sapegin
Copy link
Member

sapegin commented Nov 30, 2015

Yeah, that might work.

@sapegin sapegin mentioned this issue Dec 14, 2015
Closed
5 tasks
@stinoga
Copy link

stinoga commented Jan 12, 2016

Any work-arounds for this until version 2 comes out?

@sapegin
Copy link
Member

sapegin commented Jan 13, 2016

@stinoga I think ignoring such components is the only way now.

@stinoga
Copy link

stinoga commented Jan 13, 2016

@sapegin Does Radium cause this error as well? I've got the same error as above with a simple button component:

import React, {PropTypes} from 'react';
import classnames from 'classnames';
import Radium from 'radium';
import color from 'color';

import styles from './button.css';

class Button extends React.Component {
  render() {
    const {children, className, backgroundColor = '#0093D6', foregroundColor = '#FFFFFF', ...props} = this.props;
    let dynamicStyle = {
      backgroundColor : color(backgroundColor).hexString(),
      color : color(foregroundColor).hexString(),
      ':hover': {
        backgroundColor : color(backgroundColor).lighten(0.05).hexString(),
        boxShadow  : '0px 3px 6px 0px rgba(0,0,0,0.23), 0px 3px 6px 0px rgba(0,0,0,0.16)'
      },
      ':active': {
        backgroundColor : color(backgroundColor).darken(0.05).hexString(),
        borderBottomColor : color(backgroundColor).darken(0.05).hexString(),
        boxShadow: 'inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)'
      }
    };
    return (
      <button {...props} className={classnames(styles.button, className)} style={dynamicStyle}>
        {children}
      </button>
    );
  }
}

Button.propTypes = {
  /**
   * Set a background color on the button.
   */
  backgroundColor: PropTypes.string
};

export default Radium(Button);

@TigerC10
Copy link

@stinoga - I think I'm having the same problem. None of my Radium wrapped components are detected as suitable components.

@sapegin
Copy link
Member

sapegin commented Mar 10, 2016

@TigerC10 If you or anyone could submit a pull request to fix that it would be very cool.

@reintroducing
Copy link
Contributor

I just ran into this as well on a very simple stateless functional component. Most of my components are written this way and this is the only one that errors:

import {PropTypes, createElement} from 'react';
import classNames from 'classnames';

const List = ({
    className,
    type,
    inline,
    children
}) => {
    const classes = classNames(
        'List',
        {'List-inline': inline},
        {[`List-${type}`]: type},
        className
    );
    const tag = (type === 'ordered') ? 'ol' : 'ul';

    return createElement(
        tag,
        {
            className: classes
        },
        children
    );
};

List.propTypes = {
    className: PropTypes.string,
    type: PropTypes.oneOf(['default', 'unstyled', 'ordered']),
    inline: PropTypes.bool,
    /** Children should only be made up of the ListItem component. */
    children: PropTypes.oneOfType([
        PropTypes.element,
        PropTypes.arrayOf(PropTypes.element)
    ]).isRequired
};

List.defaultProps = {
    className: '',
    type: 'unstyled'
};

export default List;

Any idea why this one in particular would error? I can't figure it out, the component works exactly as expected.

@reintroducing
Copy link
Contributor

Nevermind, I figured it out. It's because React isn't in the component and I'm using createElement instead. React doesn't need to be there because the component doesn't really use it. Any idea on how to fix this or do I need to refactor my component and let it be there?

@tizmagik
Copy link
Collaborator

@reintroducing if you import 'react' and then use React.createElement does that help?

Another thing you can try is import 'react' and then use JSX to return like so:

const Tag = ...
return <Tag className={classes}>{children}</Tag>

@reintroducing
Copy link
Contributor

@tizmagik I ended up refactoring the component altogether and haven't gotten back to this, unfortunately. Appreciate the heads up though.

@sapegin
Copy link
Member

sapegin commented Oct 6, 2016

Please test in 4.0.0, it might be fixed.

@sapegin
Copy link
Member

sapegin commented Oct 11, 2016

Closing this for now. Feel free to reopen if you still have this issue.

@sapegin sapegin closed this as completed Oct 11, 2016
@albermav
Copy link

Hello,
I am getting the same error when using syled-components library or exporting my component using a similar methodology.
Example:

import React, { Component } from 'react';
import styled from 'styled-components';

class Button extends Component {
  render() {
    return <button>mybtn</button>;
  }
}
export default styled(Button)`
  border-color: 'red';
`;

I know this is probably a react-docgen issue... has anyone found a workaround?
Thanks guys.

@sapegin
Copy link
Member

sapegin commented Nov 28, 2016

@albermav I can reproduce it but have no idea why it doesn’t work. react-docgen can’t detect the right component for some reason.

/cc @mxstbr Could you please help with this us?

@sapegin sapegin reopened this Nov 28, 2016
@mxstbr
Copy link
Contributor

mxstbr commented Nov 29, 2016

Hmm, that's weird, styled(Button) returns a React component? This must be an issue on the react-docgen side of things, maybe?


By the way, we don't recommend using styled-components like that. This is a nicer way of doing the same thing, on top of which it works with react-docgen I'm pretty sure:

import React, { Component } from 'react';
import styled from 'styled-components';

const Btn = styled.button`
  border-color: 'red';
`;

class Button extends Component {
  render() {
    return <Btn>mybtn</Btn>;
  }
}

export default Button;

@sapegin
Copy link
Member

sapegin commented Nov 29, 2016

@mxstbr Awesome, it works! I’ve added an example to the FAQ so people could google it. Thank you very much!

@jameslaneconkling
Copy link

jameslaneconkling commented Jan 5, 2017

Documenting this here in case it's of help to anyone.

Returning a ternary from a stateless component threw the No suitable component definition found Error.

const Tooltip = ({ x, y, xOffset, yOffset, children }) => (
  typeof x === 'number' && typeof y === 'number' ? (
    <div
      style={{
        position: 'absolute',
        top: y + yOffset,
        left: x + xOffset,
        pointerEvents: 'none'
      }}
    >
      { children }
    </div>
  ) : (
    <noscript />
  )
);

Refactoring to use an if statement fixed it:

const Tooltip = ({ x, y, xOffset, yOffset, children }) => {
  if (typeof x === 'number' && typeof y === 'number') {
    return (
      <div
        style={{
          position: 'absolute',
          top: y + yOffset,
          left: x + xOffset,
          pointerEvents: 'none'
        }}
      >
        { children }
      </div>
    );
  }

  return <noscript />;
};

@sapegin
Copy link
Member

sapegin commented Jan 6, 2017

@jameslaneconkling This looks like a bug in react-docgen.

@okonet
Copy link
Member

okonet commented Oct 12, 2017

Sorry for bring this up again but it seems that the styled-components with any component still an issue. So following the official guide https://www.styled-components.com/docs/basics#styling-any-components I still can't get the component being seen by styleguidist.

cc @mxstbr

Here is my example component:

import React from 'react'
import styled from 'styled-components'

const Menu = ({children, className}) => (
  <ul className={className}>
    {children}
  </ul>
)

export default styled(Menu)`
  padding: 1rem 0;
`

@ghost
Copy link

ghost commented Nov 23, 2017

@mxstbr

By the way, we don't recommend using styled-components like that. This is a nicer way of doing the same thing, on top of which it works with react-docgen I'm pretty sure

Let me get this straight, so building a component like this is not recommended?

const RedDiv = styled.div`
  background-color: red;
`
export default RedDiv

it seems weird to me that I'd have to rewrite it to this:

const RedDiv = styled.div`
  background-color: red;
`
export default props => <RedDiv {...props} />

@mxstbr
Copy link
Contributor

mxstbr commented Nov 23, 2017

@MoeSattler no no no no that's 100% correct what you're doing there. It's just that the example given by @albermav had the class, so I kept it.

What we don't recommend:

class Button extends Component {
  render() {
    return <button className={this.props.className}>{this.props.children}</button>
  }
}

export default styled(Button)`
  color: blue;
`

Instead of doing that, do this:

const Button = styled.button`
  color: blue;
`

class BigButton extends Component {
  render() {
    return <Button>{this.props.children}</Button>
  }
}

export default BigButton;

It's even better when you can directly export the styled component, that's 100% perfect:

const Button = styled.button`
  color: blue;
`

export default Button;

That's what we want, I just assumed @albermav had a reason for the class there and this was just a trimmed-down example.

@ghost
Copy link

ghost commented Nov 23, 2017

thanks for the clarification @mxstbr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests