18

What is the proper way to document a React Higher-Order Component using JSDoc? There aren't, of course, any React-specific tags built-in - so what would be the proper approach?

Sarun UK
  • 3,862
  • 5
  • 13
  • 34
  • 1
    Well, with React, you can extract a lot of information by introspection. Unless JsDoc is strict requirement, you can do better by using something like react-styleguidist or react-docgen or bluekit. – Mrchief Oct 02 '18 at 02:45
  • side-comment: "JSDoc" from VS-Code isnt like 100% JSDoc, because you actually write typescript syntax inside of the JSDoc tags instead of "vanilla" JSDoc. – wkrueger Dec 30 '18 at 21:54
  • TypeScript, a lot better than JSDoc in many ways and is trending up – Josh Lin Nov 12 '20 at 07:39

2 Answers2

0

To document a high-order component with JSDoc, you would follow the standard as laid out below. To clarify, the documentation is usually found where the higher-order component is defined and not necessarily where it's used. If you want to document where it's used, that can be documented in that component's JSDocs as a @description, @see, @link, or other relevant tags.

  import React, { useState } from 'react';
  import Async from 'react-async';
  import { withTheme } from 'design'; // Contains the JSDoc for this HOC.
  import { getName } from 'api';

  /**
    * Component to render a greeting to someone!
    * 
    * @component
    * @param {string} userId The ID of the user to greet
    */
  export function Hello({ theme, userId }) {
    return (
      <Async promiseFn={getName} userId={userId}>
        <Async.Fulfilled>
          {(data) => <p>Hello {data.name}!</p>}
        </Async.Fulfilled>
      </Async>
    );
  };

  export default withTheme(Hello);

Documentation with React, and code in general, is always interesting. There are several ways and along with it, advantages and disadvantages of each. Ask yourself what it's going to be used for? Creating a documentation website, sharing between teammates, developers only, etc.? That being said, the most common ways to purely document are JSDoc and Markdown.

There are other ways to visualize components that have built-in documentation functionality usually based around Markdown or JSDoc as well. This becomes extremely useful when working within a team or publishing packages.

Ross Sheppard
  • 757
  • 1
  • 4
  • 12
-4

The HOC pattern is a really important tool for code reuse when building UIs in React. Prop types are helpful for catching bugs before they reach production.

Writing HOCs that properly handle the prop types of the components that they wrap, though, is difficult and requires a lot of boilerplate code. Ideally, an engineer should not shy away from moving logic to an HOC because it is too verbose to write one.

To solve this problem, react-create-hoc provides a function that implements much of this boilerplate. It allows HOCs to be created with only a straightforward function that simply wraps a component in a new component.

Usage

import React from 'react';
import PropTypes from 'prop-types';
import createHOC from 'react-create-hoc';

function WelcomeMessage({ name }) {
  return <div>{greeting}, {name}!</div>;
}

WelcomeMessage.propTypes = {
  greeting: PropTypes.string.isRequired,
  name: PropTypes.string.isRequired,
};

const withModifiedName = createHOC(
  'withModifiedName',
  (ComponentToWrap, nameModifier) => {
    function WithModifiedName({ nameProvider, ...rest }) {
      return (
        <ComponentToWrap
          name={nameModifier(nameProvider())}
          {...rest}
        />
      );
    }

    WithModifiedName.propTypes = {
      nameProvider: PropTypes.func.isRequired,
    };

    return WithModifiedName;
  },
  {
    factory: true,
    passedProps: ['name'],
  },
);

// WrappedWelcomeMessage has the following prop types:
// {
//   greeting: PropTypes.string.isRequired,
//   nameProvider: PropTypes.func.isRequired,
// }
const WrappedWelcomeMessage = withModifiedName(
  // nameModifier param
  name => name.toUpperCase(),
)(WelcomeMessage);

// Renders a div containing, "Rise and shine, MR. FREEMAN!"
ReactDOM.render(
  <WrappedWelcomeMessage
    greeting="Rise and shine"
    nameProvider={() => 'Mr. Freeman'}
  />,
  document.getElementById('root'),
);
James Delaney
  • 1,464
  • 13
  • 32