ReactJs: What should the PropTypes be for this.props.children?

好久不见. 提交于 2019-11-26 23:52:27

问题


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 children of type array supplied to ContainerComponent, expected object.

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 shape and arrayOf(shape({})) for single and array of children, respectively
  • Use oneOf for 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!