Reputation: 28780
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 valuediv
supplied toCol
,
Upvotes: 4
Views: 9491
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
Reputation: 301
Now with prop-types 15.7.0 released you can do:
Col.propTypes = {
...
containerElement: PropTypes.elementType,
}
Upvotes: 8
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
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