react button 加颜色_React组件扩展 —— 默认值、属性校验、子组件渲染和容器

本文介绍了React组件的扩展特性,包括设置属性默认值(defaultProps)、属性校验(propTypes)、渲染子组件(this.props.children)以及容器(HOC)的概念和用法。属性默认值在组件类外声明,属性校验用于避免参数错误,渲染子组件允许组件接收并处理外部传递的子元素,容器组件则用于为多个组件添加通用方法和属性。

645a4204d31b63846afb366d5a0ba8bc.png

《快速上手React编程》CH8 扩展React组件

React中可以对组件进行一些扩展,包括给属性提供默认值(defaultProps)、对属性进行校验(propTypes)、渲染子组件(this.props.children)和容器(HOC 高阶组件)。

1、属性默认值

props的默认值,只需要在组件类外面用defaultProps声明一下就好了。

class Button extends React.Component {
  render() {
    return <button className="btn" >{this.props.buttonLabel}</button>
  }
}
Button.defaultProps = {buttonLabel: 'Submit'}

如果是state需要默认值,在constructor声明的时候写一下就好了。

2、属性校验

在大型项目中,可以需要写一些给别人用的组件,为了避免别人传参错误导致各种问题,可以在自己的组件里加个属性校验。

写法是在组件类外面加个propTypes,可以用React原生的PropTypes来做验证,也可以用自定义的函数,自定义的函数需要返回一个Error,多个验证是可以用级联连在一起的,PropType.string.isRequired就是要求属性既是string又必传。

class Button extends React.Component {
  render() {
    return <button className="btn">{this.props.buttonLabel}</button>
  }
}

Button.defaultProps = {buttonLabel: 'Submit'}

Button.propTypes = {
  handler: PropTypes.func.isRequired,//多个原生校验级联在一起
  title: PropTypes.string,
  email(props, propName, componentName) {//自定义函数写验证,需要return一个Error
    let emailRegularExpression = /^([w-]+(?:.[w-]+)*)@((?:[w-]+.)*w[w-]{0,66}).([a-z]{2,6}(?:.[a-z]{2})?)$/i
    if (!emailRegularExpression.test(props[propName])) {
      return new Error('Email validation failed!')
    }
  }
}

这个类型验证如果不通过,不会出错,React只会在console里面给个Warning,一个组件里多个同样的类型验证错误会合并,只显示一个,并且只有使用未压缩版本的React才会有这个错,压缩版本的React没有这个错,因为React认为未压缩版本的React用于开发环境,压缩版用于生产,前者有错误提示,后者会把错误提示抹掉,还会有额外的性能优化。

PropTypes在React版本 >=5.5和<5.5有不同的引用方式,前者需要引一下 prop-types包,后者不用引,在React.propTypes里。也就是,老版本不用单独引,新版本需要单独引。

官方文档,有详细的原生PropTypes类型

使用 PropTypes 进行类型检查 - React​react.docschina.org
dc3de406446bc766fe9ff5d3fe5b9fce.png

3、渲染子组件

就是用一个组件的时候,它的JSX标签里面的东西,也就是下面<Content>中间的东西</Content>中间的节点们,会通过this.props.children传递给它,它可以决定把这个this.props.children放在哪里。

class Content extends React.Component {
  render() {
    return (
      <div className="content">
        {this.props.children}//直接访问外部传入的,放在Content里面的所有内容
      </div>
    )
  }
}

ReactDOM.render(
  <div>
    <Content>
      <h1>React</h1>
      <p>Rocks</p>
    </Content>
    <Content>
      <img src="images/azat.jpg" width="100"/>
    </Content>
    <Content>
      <a href="http://react.rocks">http://react.rocks</a>
    </Content>
    <Content>
      <a className="btn btn-danger" href="http://react.rocks">http://react.rocks</a>
    </Content>
  </div>,
  document.getElementById('content')
)

需要注意的是,this.props.children可能是单个对象也可能是多个对象,取决于外面传递了几个节点。单个的时候是个对象,多个的时候是个列表,所以不能用length,单个的时候会报错,可以用React.Children.count(this.props.children)算出是多少个children,多个的时候可以this.props.children[0]来访问多个,不过我觉得这玩意儿传多个容易写错。。。谁知道别人在外面怎么用这个组件的。

这种展示外部传入子元素的组件又叫展示组件/木偶组件/瘦组件。

4、容器

容器是由一个函数生成的,入参是React组件,然后在函数里给这个React组件加一些方法和属性,然后返回处理后的React组件。用于给多个组件添加通用的方法,这样就不用在多个组件内部分别写默认值了。

这个例子给传入的Component组件写了一个处理点击的通用方法属性handleClick,和一个通用属性label。然后将原来给Component的属性们通过{...this.props}扩展运算符传递给Component。

const LoadWebsite = (Component) => {
  class _LoadWebsite extends React.Component {
    constructor(props) {
      super(props)
      this.state = {label: 'Run', handleClick: this.handleClick.bind(this)} 
    }
    getUrl() {
      return 'https://facebook.github.io/react/docs/top-level-api.html'
    }
    handleClick(event) {
      document.getElementById('frame').src = this.getUrl()
    }
    componentDidMount() {
      console.log(ReactDOM.findDOMNode(this))
    }
    render() {
      console.log(this.state)
      return <Component {...this.state} {...this.props} />
    }
  }
  _LoadWebsite.displayName = 'Ehnanced1Component'//在React的调试工具里可以显示成这个名字,没有别的用途

  return _LoadWebsite
}

displayName属性的作用是在React的chrome调试插件里将处理后的组件显示成这个名字,提高调试时候的可读性,没有别的作用。

容器组件又叫智能组件/胖组件。

————————————

感觉展示组件就是透传展示了外部的子元素,提供了一个结构,外部可以填入想要的DOM;容器组件就是给多个组件提供通用的默认属性或默认方法属性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值