问题
Given a simple component that renders its children:
class ContainerComponent extends Component {
static propTypes = {
children: PropTypes.object.isRequired,
}
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
export default ContainerComponent;
Question: What should the propType of the children prop be?
When I set it as an object, it fails when I use the component with multiple children:
<ContainerComponent>
<div>1</div>
<div>2</div>
</ContainerComponent>
Warning: Failed prop type: Invalid prop
childrenof typearraysupplied toContainerComponent, expectedobject.
If I set it as an array, it will fail if I give it only one child, i.e.:
<ContainerComponent>
<div>1</div>
</ContainerComponent>
Warning: Failed prop type: Invalid prop children of type object supplied to ContainerComponent, expected array.
Please advise, should I just not bother doing a propTypes check for children elements?
回答1:
Try something like this utilizing oneOfType or PropTypes.node
import PropTypes from 'prop-types'
...
static propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]).isRequired
}
or
static propTypes = {
children: PropTypes.node.isRequired,
}
回答2:
For me it depends on the component. If you know what you need it to be populated with then you should try to specify exclusively, or multiple types using:
PropTypes.oneOfType
However I mostly find, with more generic components who can have many types of children, I'm happy to use:
PropTypes.any
If you want to refer to a React component then you will be looking for
PropTypes.element
Although,
PropTypes.node
describes anything that can be rendered - strings, numbers, elements or an array of these things. If this suits you then this is the way.
回答3:
The PropTypes documentation has the following
// Anything that can be rendered: numbers, strings, elements or an array
// (or fragment) containing these types.
optionalNode: PropTypes.node,
So, you can use PropTypes.node to check for objects or arrays of objects
static propTypes = {
children: PropTypes.node.isRequired,
}
回答4:
The answers here don't seem to quite cover checking the children exactly. node and object are too permissive, I wanted to check the exact element. Here is what I ended up using:
- Use
oneOfType([])to allow for single or array of children - Use
shapeandarrayOf(shape({}))for single and array of children, respectively - Use
oneOffor the child element itself
In the end, something like this:
import PropTypes from 'prop-types'
import MyComponent from './MyComponent'
children: PropTypes.oneOfType([
PropTypes.shape({
type: PropTypes.oneOf([MyComponent]),
}),
PropTypes.arrayOf(
PropTypes.shape({
type: PropTypes.oneOf([MyComponent]),
})
),
]).isRequired
This issue helped me figure this out more clearly: https://github.com/facebook/react/issues/2979
回答5:
If you want to match exactly a component type, check this
MenuPrimary.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(MenuPrimaryItem),
PropTypes.objectOf(MenuPrimaryItem)
])
}
If you want to match exactly some component types, check this
const HeaderTypes = [
PropTypes.objectOf(MenuPrimary),
PropTypes.objectOf(UserInfo)
]
Header.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.oneOfType([...HeaderTypes])),
...HeaderTypes
])
}
回答6:
Try a custom propTypes :
const childrenPropTypeLogic = (props, propName, componentName) => {
const prop = props[propName];
return React.Children
.toArray(prop)
.find(child => child.type !== 'div') && new Error(`${componentName} only accepts "div" elements`);
};
static propTypes = {
children : childrenPropTypeLogic
}
Fiddle
const {Component, PropTypes} = React;
const childrenPropTypeLogic = (props, propName, componentName) => {
var error;
var prop = props[propName];
React.Children.forEach(prop, function (child) {
if (child.type !== 'div') {
error = new Error(
'`' + componentName + '` only accepts children of type `div`.'
);
}
});
return error;
};
class ContainerComponent extends Component {
static propTypes = {
children: childrenPropTypeLogic,
}
render() {
return (
<div>
{this.props.children}
</div>
);
}
}
class App extends Component {
render(){
return (
<ContainerComponent>
<div>1</div>
<div>2</div>
</ContainerComponent>
)
}
}
ReactDOM.render(<App /> , document.querySelector('section'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<section />
回答7:
Example:
import React from 'react';
import PropTypes from 'prop-types';
class MenuItem extends React.Component {
render() {
return (
<li>
<a href={this.props.href}>{this.props.children}</a>
</li>
);
}
}
MenuItem.defaultProps = {
href: "/",
children: "Main page"
};
MenuItem.propTypes = {
href: PropTypes.string.isRequired,
children: PropTypes.string.isRequired
};
export default MenuItem;
Picture: Shows you error in console if the expected type is different
来源:https://stackoverflow.com/questions/42122522/reactjs-what-should-the-proptypes-be-for-this-props-children