validation - validaciones - solo permite que los niños de un tipo específico reaccionen
required react (7)
Tengo un componente de Card
y un componente de CardGroup
, y me gustaría lanzar un error cuando CardGroup
tiene hijos que no son componentes de la Card
. ¿Es esto posible, o estoy tratando de resolver el problema equivocado?
Para React 0.14+ y el uso de clases ES6, la solución se verá así:
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
}
}
Puede usar la displayName para cada niño, accediendo por tipo:
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");
}
}
Hice un PropType personalizado para esto que llamo equalTo
. Puedes usarlo así ...
class MyChildComponent extends React.Component { ... }
class MyParentComponent extends React.Component {
static propTypes = {
children: PropTypes.arrayOf(PropTypes.equalTo(MyChildComponent))
}
}
Ahora, MyParentComponent
solo acepta hijos que son MyChildComponent
. Puede verificar elementos html como este ...
PropTypes.equalTo(''h1'')
PropTypes.equalTo(''div'')
PropTypes.equalTo(''img'')
...
Aquí está la implementación ...
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.''
);
}
};
}
Podría extender esto fácilmente para aceptar uno de muchos tipos posibles. Tal vez algo como ...
React.PropTypes.equalToOneOf = function (arrayOfAcceptedComponents) {
...
}
Publiqué el paquete que permite validar los tipos de elementos 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
);
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`);
},
}
Puede agregar un apuntalante a su componente de Card
y luego buscar este accesorio en su componente CardGroup
. Esta es la forma más segura de lograr esto en React.
Este accesorio se puede agregar como un valor predeterminado por lo que siempre está ahí.
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>
)
}
}
Comprobar si el componente de la Tarjeta es efectivamente un componente de la Tarjeta utilizando el type
y displayName
no es seguro, ya que puede no funcionar durante el uso de la producción como se indica aquí: https://github.com/facebook/react/issues/6167#issuecomment-191243709
Puede usar una función propType personalizada para validar a los niños, ya que los niños son sólo accesorios. También escribí un artículo sobre esto, si quieres más detalles.
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>
);
}
});