react定义组件的两种方式,一种是函数式,一种是类的方式
返回的是一个顶级元素
一、函数组件
function Welcome(props){
return(
// <h1>hello {props.name}</h1>
// <h1>hello {props.name}</h1> //不可以这样写,JSX必须要有一个顶级的父元素来包裹下面的子元素
<div> //只能有一个根元素
<h1>hello {props.name}</h1>
<h1>你好 {props.name}</h1>
</div>
)
}
ReactDOM.render(<Welcome name="leah"></Welcome>,document.getElementById('root'))
数式定义的是无状态组件,
无状态组件的创建形式使代码的可读性更好,并且减少了大量冗余的代码,精简至只有一个render方法,大大的增强了编写一个组件的便利,除此之外无状态组件还有以下几个显著的特点:
- 组件不会被实例化,整体渲染性能得到提升
因为组件被精简成一个render方法的函数来实现的,由于是无状态组件,所以无状态组件就不会在有组件实例化的过程,无实例化过程也就不需要分配多余的内存,从而性能得到一定的提升。 - 组件不能访问this对象
无状态组件由于没有实例化过程,所以无法访问组件this中的对象,例如:this.ref、this.state等均不能访问。若想访问就不能使用这种形式来创建组件 - 组件无法访问生命周期的方法
因为无状态组件是不需要组件生命周期管理和状态管理,所以底层实现这种形式的组件时是不会实现组件的生命周期方法。所以无状态组件是不能参与组件的各个生命周期管理的。 - 无状态组件只能访问输入的props,同样的props会得到同样的渲染结果,不会有副作用
无状态组件被鼓励在大型项目中尽可能以简单的写法来分割原本庞大的组件,未来React也会这种面向无状态组件在譬如无意义的检查和内存分配领域进行一系列优化,所以只要有可能,尽量使用无状态组件。
二、类组件
class Welcome extends React.Component{ //继承自父组件的方法和属性
constructor(props){
super(props)
}
render(){
return (
<div>
<h1>hello {this.props.name}</h1>
<h1>你好 {this.props.name}</h1>
</div>
)
}
}
//React是通过首字母是否大写来区分是内置的原生DOM组件(div、span、h1)和自定义组件,组件的首字母都要大写
ReactDOM.render(<Welcome name="leah"></Welcome>,document.getElementById('root'))
类组件是用React.Component+ES6的方法创建的,React.Component
创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。
三、复合组件
class Panel extends React.Component{
constructor(props){
super(props)
}
render(){
return(
<div className="panel panel-default">
<div className="panel-heading">
我是头部
</div>
<div className="panel-body">
我是主体
</div>
<div className="panel-footer">
我是尾部
</div>
</div>
)
}
}
ReactDOM.render(<Panel></Panel>,document.getElementById('root'))
这个组件包含三个部分,我们可以把每个部分都拆分成一个小组件
class PanelHeading extends React.Component{
render(){
return(
<div className="panel-heading">
我是头部
</div>
)
}
}
class PanelBody extends React.Component{
render(){
return(
<div className="panel-heading">
我是主体
</div>
)
}
}
class PanelFooter extends React.Component{
render(){
return(
<div className="panel-footer">
我是主体
</div>
)
}
}
class Panel extends React.Component{
constructor(props){
super(props)
}
render(){
return(
<div className="panel panel-default">
<PanelHeading color="blue"></PanelHeading>
<PanelBody color="blue"></PanelBody>
<PanelFooter color="blue"></PanelFooter>
</div>
)
}
}
ReactDOM.render(<Panel></Panel>,document.getElementById('root'))
通过这种方式定义的组件可以继承自父组件的属性,也就是说父组件通过props的形式给子组件传递属性
class PanelHeading extends React.Component{
render(){
return(
<div className="panel-heading" style={{color: `${this.props.color}`}}>
我是头部
</div>
)
}
}
class PanelBody extends React.Component{
render(){
return(
<div className="panel-heading" style={{color: `${this.props.color}`}}>
我是主体
</div>
)
}
}
class PanelFooter extends React.Component{
render(){
return(
<div className="panel-footer" style={{color: `${this.props.color}`}}>
我是主体
</div>
)
}
}
class Panel extends React.Component{
constructor(props){
super(props)
}
render(){
return(
<div className="panel panel-default" style={{background:'red'}}>
<PanelHeading color="blue"></PanelHeading>
<PanelBody color="orange"></PanelBody>
<PanelFooter color="grean"></PanelFooter>
</div>
)
}
}
ReactDOM.render(<Panel></Panel>,document.getElementById('root'))
四、props属性校验
React提供了PropTypes这个对象用于校验属性的类型,PropTypes包含组件属性的所有可能类型,下面看看组件属性类型和propTypes属性的对应关系
下面看一个例子
首先安装校验模块,现在这个校验规则被抽离出来成了一个单独的模块
安装
npm install --save prop-types
引入
import PropTypes from 'prop-types';
class Person extends React.Component{
static propTypes = {
age: PropTypes.number,
gender: PropTypes.oneOf(['male','female']).isRequired,
hobby: PropTypes.arrayOf(PropTypes.string).isRequired,
}
render() {
return (
<div>
<div>个人资料</div>
<div>年龄:{this.props.age}</div>
<div>性别:{this.props.gender}</div>
<div>爱好:{this.props.hobby}</div>
<div>坐标:{this.props.position}</div>
</div>
)
}
}
let prop = {
age: 18,
gender: 'male',
hobby: ['basktaball','football'],
friends: [{name:'zhangsan',age:10},{name: 'lisi',age:20}]
}
ReactDOM.render(<Person {...prop}></Person>,document.getElementById('root'))