Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React propTypes component class?

How can I validate that the supplied prop is a component class (not instance)?

e.g.

export default class TimelineWithPicker extends React.PureComponent {

    static propTypes = {
        component: PropTypes.any, // <-- how can I validate that this is a component class (or stateless functional component)?
    };

    render() {
        return (
            <this.props.component {...this.props} start={this.state.start}/>
        );
    }
}
like image 833
mpen Avatar asked Jul 26 '17 01:07

mpen


People also ask

What is the PropTypes for a React component?

Using PropTypes in React PropTypes is React's internal mechanism for adding type checking to components. React components use a special property named propTypes to set up type checking.

Can we use PropTypes in functional component?

Firstly, npm install / yarn add the prop-types package if you haven't already. Then, add your propTypes (and defaultProps too if required) after the stateless functional component has been defined, before you export it.

Is PropTypes deprecated?

PropTypes is deprecated since React 15.5.

Should PropTypes be a dev dependency?

javascript - 'prop-types' should be listed in the project's dependencies, not devDependencies - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.


2 Answers

For anyone using PropTypes >= 15.7.0 a new PropTypes.elementType was added in this pull request and was released on february 10, 2019.

This prop type supports all components (native components, stateless components, stateful components, forward refs React.forwardRef, context providers/consumers).

And it throws a warning when is not any of those elements, it also throws a warning when the prop passed is an element (PropTypes.element) and not a type.

Finally you can use it like any other prop type:

const propTypes = {     component: PropTypes.elementType,     requiredComponent: PropTypes.elementType.isRequired, }; 
like image 72
Jose Da Silva Avatar answered Sep 29 '22 11:09

Jose Da Silva


EDITED: Added React's FancyButton example to codesandbox as well as a custom prop checking function that works with the new React.forwardRef api in React 16.3. The React.forwardRef api returns an object with a render function. I'm using the following custom prop checker to verify this prop type. - Thanks for Ivan Samovar for noticing this need.

FancyButton: function (props, propName, componentName) {
  if(!props[propName] || typeof(props[propName].render) != 'function') {
    return new Error(`${propName}.render must be a function!`);
  }
}

You'll want to use PropTypes.element. Actually... PropType.func works for both stateless functional components and class components.

I've made a sandbox to prove that this works... Figured this was needed considering I gave you erroneous information at first. Very sorry about that!

Working sandbox example!

Here is the code for the test in case link goes dead:

import React from 'react';
import { render } from 'react-dom';
import PropTypes from "prop-types";

class ClassComponent extends React.Component {
  render() {
    return <p>I'm a class component</p>
  }
}

const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

const FSComponent = () => (
    <p>I'm a functional stateless component</p>
);

const Test = ({ ClassComponent, FSComponent, FancyButton }) => (
  <div>
    <ClassComponent />
    <FSComponent />
    <FancyButton />
  </div>
);
Test.propTypes = {
  ClassComponent: PropTypes.func.isRequired,
  FSComponent: PropTypes.func.isRequired,
  FancyButton: function (props, propName, componentName) {
    if(!props[propName] || typeof(props[propName].render) != 'function') {
      return new Error(`${propName}.render must be a function!`);
    }
  },
}

render(<Test
         ClassComponent={ ClassComponent }
         FSComponent={ FSComponent }
         FancyButton={ FancyButton } />, document.getElementById('root'));
like image 21
Kyle Richardson Avatar answered Sep 29 '22 10:09

Kyle Richardson