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

Doesn't find HOCs that just wrap & re-export component

Open jdiefen opened this issue 7 years ago • 10 comments

Some HOCs aren't correctly parsed when they're just calling a function on an imported component. For example, exporting a HelloButton component that just exports an imported Button component wrapped in redux connect:

hello-button.js:

// @flow
import { connect } from 'react-redux';

import { sayHello } from '../actions/hello';
import Button from '../components/Button';

const mapStateToProps = () => ({
        label: 'Say something',
});

const mapDispatchToProps = dispatch => ({
        handleClick: () => {
                dispatch(sayHello('Hi!!!'));
        },
});

// HelloButton
export default connect(mapStateToProps, mapDispatchToProps)(Button);

button.js:

// @flow
import React from 'react';
import './index.css';

type Props = {
        label: string,
        handleClick: Function
};

const Button = ({ label, handleClick }: Props) =>
        <button styleName='button' onClick={handleClick}>{label}</button>
;

export default Button;

Button is properly parsed, but HelloButton is not considered a component, even when using the findAllComponentDefinitions resolver.

jdiefen avatar Apr 16 '17 13:04 jdiefen

react-docgen only looks at files in isolation. It doesn't know that Button inside hello-button.js is a React component.

What would you expect the result for hello-button.js to be? It shouldn't be difficult to write a custom resolver that finds connect calls.

fkling avatar Apr 17 '17 04:04 fkling

Ah, that makes more sense! I thought it did (or was supposed to do) cross-file resolution too.

Writing a resolver that finds connect calls might not be too difficult...I'm honestly just hoping to find a documentation-generation tool that can parse my React/Flow code. Basically, just JSDoc + React/Flow parsing.

Thanks for the clarification :)

jdiefen avatar Apr 18 '17 13:04 jdiefen

I'm having the same issue with a different type of HOC. Is there a way we could manually hint to the parser (through comment or code) that something returns a React component? Making exceptions for specific ones probably isn't sustainable, given the number of them out there (Radium, Aphrodite, Relay, recompose, react-redux, ...rest).

import { compose, withState, withHandlers } from "recompose";

const FixedComponent: Class<Component<Props, null, null>> = compose(
  withState("fixed", "setFixed", false),
  withHandlers({
    onEnter: props => () => props.setFixed(false),
    onLeave: props => () => props.setFixed(true),
  }),
)(Component);

threehams avatar May 05 '17 23:05 threehams

@threehams: Yeah, I just recently thought about that too. Do you have something concrete in mind?

fkling avatar May 08 '17 20:05 fkling

Could use jsdoc's @type. I'd be a little concerned about piggybacking on existing tags - would there be cases that work now, but would break with something like this? (I have very little experience with jsdoc so I'm not sure if there are major downsides here.)

/**
 * Fixes the component to the top of the page after scrolling past it.
 * @type React.Component
 * or
 * @type Component
 */
const FixedComponent: Class<Component<Props, null, null>> = compose(
// etc

It feels a bit strange to have to add a jsdoc tag when using Flow, but typing HOCs is very experimental right now.

threehams avatar May 09 '17 03:05 threehams

Hi, looks like this is a deal breaker for people using recompose to create their components.

Is there any progress on this front?

FezVrasta avatar Oct 02 '17 14:10 FezVrasta

@FezVrasta: Maybe https://github.com/Jmeyering/react-docgen-annotation-resolver helps you.

The general problem is that there is no standard format for HOCs. A possible solution is to write custom resolvers and handlers for specific types of HOCs, but these have to come from the community.

If you are interested in doing that for recompose, have a look at the default resolvers and handlers, and how they work. I'm also happy to answer any questions regarding this.

fkling avatar Oct 11 '17 16:10 fkling

Isn't there any way to manually mark a function as "component"? Maybe with a comment, or a regex?

In my case I only export default components, so I would just like react-docgen to use them all..

FezVrasta avatar Oct 11 '17 16:10 FezVrasta

@FezVrasta: The resolver I linked to allows you to do that.

fkling avatar Oct 11 '17 20:10 fkling

@FezVrasta: The resolver I linked to allows you to do that.

Do you happen to know how to use that resolver?

I'm putting this into my plugins list in .babelrc but nothing happens:

[
    "babel-plugin-react-docgen",
    {
      "resolver": "react-docgen-annotation-resolver",
      "removeMethods": true
    }
  ]

Of course, I tagged the component I wanted to be taken into account by react-docgen like this:

const myComponent = () => (
  <h1>Component</h1>
);

/**
 * @component
 */
export default withCustomHOC(myComponent);

Richacinas avatar Aug 14 '19 08:08 Richacinas