Card
コンポーネントとCardGroup
コンポーネントがあり、CardGroup
がCard
コンポーネントではない子を持つ場合にエラーをスローしたいと思います。これは可能ですか、それとも間違った問題を解決しようとしていますか?
タイプを介してアクセスされる各子の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");
}
}
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
}
}
子は単なる小道具なので、カスタムpropType関数を使用して子を検証できます。さらに詳細が必要な場合は、これについて 記事 も書いています。
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>
);
}
});
equalTo
を呼び出すカスタムPropTypeを作成しました。このように使用できます...
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) {
...
}
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`);
},
}
型の不一致エラーを回避するためにTypeScriptを使用している場合は、「child.type」とともに「React.isValidElement(child)」を使用する必要があります。
React.Children.forEach(props.children, (child, index) => {
if (React.isValidElement(child) && child.type !== Card) {
error = new Error(
'`' + componentName + '` only accepts children of type `Card`.'
);
}
});
正しい子コンポーネントを検証するには、 react children foreach と カスタム検証proptypes の使用を組み合わせるため、最後に次のようになります。
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
};
ご覧のとおり、正しい型の名前を持つ配列があります。
一方、airbnb/prop-typesライブラリには、同じ結果を得るのに役立つcomponentWithNameという関数もあります。 ここで詳細を確認できます
HouseComponent.propTypes = {
children: PropTypes.oneOfType([
componentWithName('SegmentedControl'),
componentWithName('FormText'),
componentWithName('FormTextarea'),
componentWithName('FormSelect')
]).isRequired
};
これが何らかの助けになることを願っています:)
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.");
}
}
uglifyに関するメンテナンスと安定性を向上させるために、Card.name
文字列の代わりに'Card'
文字列を使用することをお勧めします。
参照: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
Card
コンポーネントに小道具を追加し、CardGroup
コンポーネントでこの小道具を確認できます。これは、Reactでこれを達成する最も安全な方法です。
このプロップはdefaultPropとして追加できるため、常にそこにあります。
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
またはdisplayName
を使用してCardコンポーネントが実際にCardコンポーネントであるかどうかを確認することは安全ではありません。以下に示すように、実稼働使用中に動作しない可能性があります。 https:// github .com/facebook/react/issues/6167#issuecomment-191243709
私のような人には、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;
});
React elements 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
);
私にとってこれを達成する最も簡単な方法は、次のコードです。
例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;