《快速上手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 进行类型检查 - Reactreact.docschina.org
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;容器组件就是给多个组件提供通用的默认属性或默认方法属性。
本文介绍了React组件的扩展特性,包括设置属性默认值(defaultProps)、属性校验(propTypes)、渲染子组件(this.props.children)以及容器(HOC)的概念和用法。属性默认值在组件类外声明,属性校验用于避免参数错误,渲染子组件允许组件接收并处理外部传递的子元素,容器组件则用于为多个组件添加通用方法和属性。


被折叠的 条评论
为什么被折叠?



