only allow children of a specific type in a react component

后端 未结 14 1650
天涯浪人
天涯浪人 2020-11-29 00:59

I have a Card component and a CardGroup component, and I\'d like to throw an error when CardGroup has children that aren\'t Card

相关标签:
14条回答
  • 2020-11-29 01:32

    Use the React.Children.forEach method to iterate over the children and use the name property to check the type:

    React.Children.forEach(this.props.children, (child) => {
        if (child.type.name !== Card.name) {
            console.error("Only card components allowed as children.");
        }
    }
    

    I recommend to use Card.name instead of 'Card' string for better maintenance and stability in respect to uglify.

    See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

    0 讨论(0)
  • 2020-11-29 01:33

    For me the simplest way to achieve this was following code.

    Example 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;
    

    Example 2 - With Component

    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;
    
    0 讨论(0)
  • For React 0.14+ and using ES6 classes, the solution will look like:

    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
      }
    }
    
    0 讨论(0)
  • 2020-11-29 01:37

    One has to use "React.isValidElement(child)" along with "child.type" if one is working with Typescript in order to avoid type mismatch errors.

    React.Children.forEach(props.children, (child, index) => {
      if (React.isValidElement(child) && child.type !== Card) {
        error = new Error(
          '`' + componentName + '` only accepts children of type `Card`.'
        );
      }
    });
    
    0 讨论(0)
  • 2020-11-29 01:38

    You can use a custom propType function to validate children, since children are just props. I also wrote an article on this, if you want more details.

    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>
        );
      }
    });
    
    0 讨论(0)
  • 2020-11-29 01:38

    You can add a prop to your Card component and then check for this prop in your CardGroup component. This is the safest way to achieve this in React.

    This prop can be added as a defaultProp so it's always there.

    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>
        )
      }
    }
    

    Checking for whether the Card component is indeed a Card component by using type or displayName is not safe as it may not work during production use as indicated here: https://github.com/facebook/react/issues/6167#issuecomment-191243709

    0 讨论(0)
提交回复
热议问题