只允许反应组件中特定类型的子项

big*_*ind 41 validation reactjs

我有一个Card组件和一个CardGroup组件,当CardGroup有子Card组件不是组件时,我想抛出一个错误.这是可能的,还是我试图解决错误的问题?

Die*_*o V 43

对于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
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我不知道为什么,但```child.type === Card```在我的设置中不起作用.但是我通过使用```child.type.prototype instanceof Card```来实现它.我的React版本是15.5.4 (13认同)
  • @ user2167582因为这是prop验证函数的预期API.[官方文档](https://github.com/facebook/prop-types/blob/master/README.md)在示例代码中包含以下注释:_您还可以指定自定义验证器.如果验证失败,它应该返回一个Error对象.不要'console.warn`或throw,因为这在`oneOfType`_里面不起作用. (3认同)
  • `child.type`的文档在哪里?有人可以发送链接吗? (3认同)

Mar*_*ark 19

您可以为每个子项使用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");
  }  
}
Run Code Online (Sandbox Code Playgroud)

  • 请记住,使用像Uglify这样的东西会打破这个 (14认同)
  • 你不应该这样做因为`props.children`是[不透明的数据类型](https://en.wikipedia.org/wiki/Opaque_data_type).更好地使用`React.Children`实用程序,如[here](http://stackoverflow.com/a/36424582/1385678)所示. (8认同)
  • 确保检查当前环境是开发还是生产.propTypes验证不会在生产中触发性能.在propTypes中使用customProp会很有帮助. (4认同)
  • 正如@RyanRho 指出的那样,这可能会导致在生产模式下运行 React 时出现问题。相反,我向子组件添加了一个 defaultProp,例如 `static defaultProps = { isCard: true}` 然后检查了这个,例如 `if (!this.props.children[child].props.isCard) { ... }` (3认同)
  • 那“帮助了我”,但是我使用了“名称”而不是“ displayName”(最后一个对我不起作用) (3认同)
  • 切勿使用displayName,因为在生产中可能会剥离它! (3认同)

mza*_*kie 14

您可以使用自定义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>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

  • 混淆后,```child.type.displayName```无法正常工作 (2认同)

SLC*_*000 8

对于那些使用 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;
        });
Run Code Online (Sandbox Code Playgroud)


Sal*_*lim 8

使用该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.");
    }
}
Run Code Online (Sandbox Code Playgroud)

我建议使用Card.name代替'Card'string 来更好地维护和稳定uglify

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


小智 6

如果使用 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`.'
    );
  }
});
Run Code Online (Sandbox Code Playgroud)


Hed*_*ith 5

您可以向组件添加一个 prop Card,然后在组件中检查此 prop CardGroup。这是在 React 中实现此目的最安全的方法。

该 prop 可以添加为 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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

检查 Card 组件是否确实是 Card 组件,type或者displayName不安全,因为它在生产使用期间可能无法工作,如下所示:https ://github.com/facebook/react/issues/6167#issuecomment-191243709