dagda1
dagda1

Reputation: 28780

What is the correct PropTypes for component or element

I am creating a component that I want the element type to be configurable.

const Col = ({ containerElement, children }) => {
  return (
    <containerElement>
      {children}
    </containerElement>
  );
};

Col.defaultProps = {
  containerElement: 'div'
};

So container element could either be as in the defaultProps above or it could be a component.

<Col containerElement={<MyComponent} />

I can't get the propTypes to validate, I have tried this:

Col.propTypes = {
  className: PropTypes.string,
  containerElement: PropTypes.oneOf([
    PropTypes.string,
    PropTypes.element
  ]),

But it does not validate correctly.

Warning: Failed propType: Invalid prop componentClass of value div supplied to Col,

Upvotes: 4

Views: 9491

Answers (4)

0MR4N
0MR4N

Reputation: 101

There is some wrong stuffs in your code:

you put a non-capitalize react component (which exists in the element's props):

const Col = ({ containerElement, children }) => {
  return (
    <containerElement>    // <---this should start with uppercase letter
      {children}
    </containerElement>
  );
};

Col.defaultProps = {
  containerElement: 'div' // this should be Componenet type not string
};

React Components always should start with capital letter else it will be conflicted with html elements

Col.propTypes = {
  className: PropTypes.string,
  containerElement: PropTypes.oneOf([ // you should use PropTypes.oneOfType
    PropTypes.string,
    PropTypes.element
  ])

PropTypes.oneOf is used to indicate that the value should be in the array argument.

PropTypes.oneOfType is used to indicate that the value's type shoudl be in the array argument.

if we say Component.propTypes = { theme: PropTypes.oneOf(["dark", "light"])} we indicate that the value of theme props should be either dark or light.

if we say Component.propTypes = { data: PropTypes.oneOfType([PropTypes.string, PropTypes.number])} we indicate that type of the data prop should be string or number.

before i show you a demo code that i wrote you should know the difference between component and component element. if you know so you can skip this part:

component is: Component and it's type is PropTypes.elementType. component element is <Componenet /> or <Component>...</Component> and it's type is PropTypes.element.

*here is my demo code if you have any propblem or didn't understand it, feel

free to ask:*
import { oneOfType, string, element, elementType } from 'prop-types';
import { Fragment } from 'react';

// defining test component
function Test({ Element, ElementType }) {
  console.log(ElementType)
  return (
    <ElementType> {/* <--- [*] Note React Component Should be capitalized */}
      Here is Element : {Element}
    </ElementType>
  )
}
// default props for Test
Test.defaultProps = {
  Element: <u>default element</u>,
  ElementType: Fragment

}

// define propTypes for Test
Test.propTypes = {
  Element: oneOfType([string, element]), // <-- you should use oneOfType not oneOf
  ElementType: elementType
}

// define Wrapper component
function Wrapper({ children }) {
  return (
    <div style={{ backgroundColor: "lightgreen" }}>
      {children}
    </div>
  )
}



export default function App() {
  return (
    <>
      <Test />
      <hr />
      <Test ElementType={Wrapper} />
      <hr />
      <Test Element="hi i am element prop (string type)" />
      <hr />
      <Test Element={<b>hi another time (element type)</b>} ElementType={Wrapper} />
    </>

  )
}

Upvotes: 3

Elad Levy
Elad Levy

Reputation: 301

Now with prop-types 15.7.0 released you can do:

Col.propTypes = {
  ...
  containerElement: PropTypes.elementType,
}

Upvotes: 8

Limbo
Limbo

Reputation: 2290

Try this:

Col.propTypes = {
    className: PropTypes.string,
    containerElement: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.func
    ]),
}

because React components are functions in a global sense, and

typeof (class MyClass {}) // => "function"

Upvotes: 1

Bartek Fryzowicz
Bartek Fryzowicz

Reputation: 6674

You don't have componentClass property defined on your component - your prop is called containerElement and you should use oneOfType:

Col.propTypes = {
  className: PropTypes.string,
  containerElement: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.element
  ])

Upvotes: 1

Related Questions