我有一个Card
组件和一个CardGroup
组件,当CardGroup
的子组件不是Card
组件时,我想抛出一个错误。这是可能的,还是我试图解决错误的问题?
答案 0 :(得分:41)
对于React 0.14+并使用ES6类,解决方案将如下所示:
class CardGroup extends Component {
render() {
return (
<div>{this.props.children}</div>
)
}
}
CardGroup.propTypes = {
children: function (props, propName, componentName) {
const prop = props[propName]
let error = null
React.Children.forEach(prop, function (child) {
if (child.type !== Card) {
error = new Error('`' + componentName + '` children should be of type `Card`.');
}
})
return error
}
}
答案 1 :(得分:17)
您可以为每个孩子使用displayName,可通过以下类型访问:
for (child in this.props.children){
if (this.props.children[child].type.displayName != 'Card'){
console.log("Warning CardGroup has children that aren't Card components");
}
}
答案 2 :(得分:13)
您可以使用自定义propType函数来验证孩子,因为孩子只是道具。如果你想了解更多细节,我还在此写了article。
var CardGroup = React.createClass({
propTypes: {
children: function (props, propName, componentName) {
var error;
var prop = props[propName];
React.Children.forEach(prop, function (child) {
if (child.type.displayName !== 'Card') {
error = new Error(
'`' + componentName + '` only accepts children of type `Card`.'
);
}
});
return error;
}
},
render: function () {
return (
<div>{this.props.children}</div>
);
}
});
答案 3 :(得分:4)
static propTypes = {
children : (props, propName, componentName) => {
const prop = props[propName];
return React.Children
.toArray(prop)
.find(child => child.type !== Card) && new Error(`${componentName} only accepts "<Card />" elements`);
},
}
答案 4 :(得分:3)
我为此制作了一个自定义PropType,我称之为equalTo
。你可以像这样使用它......
class MyChildComponent extends React.Component { ... }
class MyParentComponent extends React.Component {
static propTypes = {
children: PropTypes.arrayOf(PropTypes.equalTo(MyChildComponent))
}
}
现在,MyParentComponent
只接受MyChildComponent
的孩子。你可以检查这样的html元素......
PropTypes.equalTo('h1')
PropTypes.equalTo('div')
PropTypes.equalTo('img')
...
这是实施......
React.PropTypes.equalTo = function (component) {
return function validate(propValue, key, componentName, location, propFullName) {
const prop = propValue[key]
if (prop.type !== component) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
};
}
您可以轻松扩展此选项以接受多种可能类型中的一种。也许像是......
React.PropTypes.equalToOneOf = function (arrayOfAcceptedComponents) {
...
}
答案 5 :(得分:2)
您可以在<?php
function foo($optionsgiven = array())
{
$defaultoptions = ['width' => 10, 'height' => 20, 'weight' => 30];
foreach($defaultoption as $key => $value) {
if(isset($optionsgiven[$key])) {
$options[$key] = $optionsgiven[$key];
}
else {
$options[$key] = $value;
}
}
}
// main script
$x = foo(['width' => 100]);
?>
组件中添加道具,然后在Card
组件中检查此道具。这是在React中实现这一目标的最安全的方法。
这个道具可以作为defaultProp添加,因此它始终存在。
CardGroup
使用class Card extends Component {
static defaultProps = {
isCard: true,
}
render() {
return (
<div>A Card</div>
)
}
}
class CardGroup extends Component {
render() {
for (child in this.props.children) {
if (!this.props.children[child].props.isCard){
console.error("Warning CardGroup has a child which isn't a Card component");
}
}
return (
<div>{this.props.children}</div>
)
}
}
或type
检查卡组件是否确实是卡组件是不安全的,因为它在生产使用期间可能无效,如下所示:https://github.com/facebook/react/issues/6167#issuecomment-191243709
答案 6 :(得分:2)
对于像我这样的人,使用TypeScript版本。 您可以像这样过滤/修改组件:
this.modifiedChildren = React.Children.map(children, child => {
if (React.isValidElement(child) && (child as React.ReactElement<any>).type === Card) {
let modifiedChild = child as React.ReactElement<any>;
// Modifying here
return modifiedChild;
}
// Returning other components / string.
// Delete next line in case you dont need them.
return child;
});
答案 7 :(得分:2)
如果正在使用Typescript以避免类型不匹配错误,则必须使用“React.isValidElement(child)”和“child.type”。
React.Children.forEach(props.children, (child, index) => {
if (React.isValidElement(child) && child.type !== Card) {
error = new Error(
'`' + componentName + '` only accepts children of type `Card`.'
);
}
});
答案 8 :(得分:1)
我发布了允许验证React元素https://www.npmjs.com/package/react-element-proptypes的类型的包:
const ElementPropTypes = require('react-element-proptypes');
const Modal = ({ header, items }) => (
<div>
<div>{header}</div>
<div>{items}</div>
</div>
);
Modal.propTypes = {
header: ElementPropTypes.elementOfType(Header).isRequired,
items: React.PropTypes.arrayOf(ElementPropTypes.elementOfType(Item))
};
// render Modal
React.render(
<Modal
header={<Header title="This is modal" />}
items={[
<Item/>,
<Item/>,
<Item/>
]}
/>,
rootElement
);
答案 9 :(得分:1)
要验证正确的子组件,我结合使用react children foreach和Custom validation proptypes,最后您可以拥有以下内容:
SELECT o.order_id, o.order_date, cu.customer_city,
cu.customer_first_name, cu.customer_last_name
FROM orders o
INNER JOIN customers cu
on o.customer_id = cu.customer_id
正如您所看到的那样,正在使用正确类型的名称和数组。
另一方面,airbnb / prop-types库中还有一个名为componentWithName的函数,它有助于获得相同的结果。 Here you can see more details
HouseComponent.propTypes = {
children: PropTypes.oneOfType([(props, propName, componentName) => {
let error = null;
const validInputs = [
'Mother',
'Girlfried',
'Friends',
'Dogs'
];
// Validate the valid inputs components allowed.
React.Children.forEach(props[propName], (child) => {
if (!validInputs.includes(child.type.name)) {
error = new Error(componentName.concat(
' children should be one of the type:'
.concat(validInputs.toString())
));
}
});
return error;
}]).isRequired
};
希望这对某人有所帮助:)
答案 10 :(得分:1)
使用React.Children.forEach
方法遍历子对象,并使用name
属性检查类型:
React.Children.forEach(this.props.children, (child) => {
if (child.type.name !== Card.name) {
console.error("Only card components allowed as children.");
}
}
我建议使用Card.name
代替'Card'
字符串,以更好地维护和稳定 uglify 。
请参阅:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
答案 11 :(得分:1)
考虑了多种提议的方法,但事实证明它们都不可靠或过于复杂,无法用作样板。解决了以下实现问题。
class Card extends Component {
// ...
}
class CardGroup extends Component {
static propTypes = {
children: PropTypes.arrayOf(
(propValue, key, componentName) => (propValue[key].type !== Card)
? new Error(`${componentName} only accepts children of type ${Card.name}.`)
: null
)
}
// ...
}
以下是关键思想:
PropTypes.arrayOf()
而不是遍历子对象propValue[key].type !== Card
在自定义验证器中检查子类型${Card.name}
不会硬编码类型名称库react-element-proptypes在ElementPropTypes.elementOfType()
中实现此目的:
import ElementPropTypes from "react-element-proptypes";
class CardGroup extends Component {
static propTypes = {
children: PropTypes.arrayOf(ElementPropTypes.elementOfType(Card))
}
// ...
}
答案 12 :(得分:0)
对我来说,最简单的方法是遵循以下代码。
示例1:
import React, {Children} from 'react';
function myComponent({children}) {
return (
<div>{children && Children.map(children, child => {
if (child.type === 'div') return child
})}</div>
)
}
export default myComponent;
示例2-具有组件
import React, {Children} from 'react';
function myComponent({children}) {
return (
<div>{children && Children.map(children, child => {
if (child.type.displayName === 'Card') return child
})}</div>
)
}
export default myComponent;
答案 13 :(得分:0)
输入类型:
props.children.forEach(child =>
console.assert(
child.type.name == "CanvasItem",
"CanvasScroll can only have CanvasItem component as children."
)
)
答案 14 :(得分:0)
简单、生产友好的检查。在 CardGroup 组件的顶部:
const cardType = (<Card />).type;
然后,在迭代子项时:
React.children.map(child => child.type === cardType ? child : null);
这项检查的好处在于,它也适用于不公开使 instanceof
检查工作所需的类的库组件/子组件。