# 组件声明
React
中声明组件有两种方式,一是函数式组件,就是把一个函数作为组件的构造器;二是 class
组件,即用 ES6
的 class
语法声明一个类作为组件的构造器。在 16.8 版本以前函数式组件不能使用组件的 state
, refs
属性等诸多特性,这使得函数式组件只能用来定义一些简单组件,对于复杂一些的组件只能使用 class
组件。而此版本以后 React
加入了 Hook
,使得函数式组件也能够使用组件的其它特性。官方文档
# 函数式组件
函数式组件中我们只能用 props
属性,定义一个函数式组件只需要创建一个开头为大写字母的函数,然后再将函数最后 return
回一个 jsx
标签即可。代码如下:
function Person(props) { | |
return ( | |
<div> | |
<h2>{props.name}</h2> | |
</div> | |
) | |
} | |
ReactDOM.render(<Person name="Asuhe" />,document.querySelector('#root')) |
# class 组件
class
组件要比函数式组件强大的多,它可以完全使用组件三大属性: state
、 props
、 refs
。它还有生命周期函数可供使用,在生命周期函数中我们可以进行许多操作。但创建一个 class
组件需要从 React对象
中继承一个类 React.Component
。代码如下:
class MyComponent extends React.Component { | |
//render 函数必须要有 | |
render(){ | |
return ( | |
<div> | |
<h2>Asuhe</h2> | |
</div> | |
) | |
} | |
} | |
ReactDOM.render(<MyComponent />,document.querySelector('#root')) |
当我们需要在 class
组件上挂载事件处理函数时有两种方式,一是在 constructor
中重写该事件处理函数,二是利用箭头函数和 class 语法声明函数。
class Weather extends React.Component { | |
/* 第一种方法 在 jsx 中调用的 this 调用 weather 和设置 state | |
constructor (props) { | |
super (props) | |
this.state = { isHot: true, breeze: ' 微风 ' } | |
// 关键步骤:将原型上的 changeWeather 挂载载到组件实例对象的 changeWeather 里并更改 this | |
this.changeWeather = this.changeWeather.bind (this) | |
} | |
changeWeather () { | |
let {isHot} = this.state | |
this.setState ({ | |
isHot: !isHot | |
}) | |
} | |
// 未重写 changeWeather 前,onClick 绑定的 this.changeWeather 相当于 | |
//let a = new Weather () | |
//let x = a.changeWeather | |
//x () | |
*/ | |
// 第二种方法 不在原型上挂载 changeWeather | |
state = { isHot: true, breeze: '微风' } | |
changeWeather = () => { | |
let { isHot } = this.state | |
this.setState({ | |
isHot: !isHot | |
}) | |
} | |
render() { | |
return ( | |
<h2 onClick={this.changeWeather}> | |
今天天气很{this.state.isHot ? '炎热' : '凉爽'},{this.state.breeze} | |
</h2> | |
) | |
} | |
} | |
ReactDOM.render(<Weather />, el) |
# 组件的三大属性
组件实例中有很多属性,但比较常用的就三个分别是:state、props、refs。
# state
state
属性是用来存储该组件实例的状态的。当我们使用 this.setState
函数去修改 state
时,页面会因为组件状态改变而同步改变。以上面的 MyComponent
组件为例,我们可以给组件定义一个初始状态:
class MyComponent extends React.Component { | |
/* 第一种方式在构造器里初始化状态 | |
constructor (props){ | |
// 使用了构造器就一定要调用 super 否则 React 报错 | |
super (props) | |
this.state = {name:'Asuhe'} | |
// 若不给 super 传 props,则在 constructor 中使用 this.props 可能会出错 | |
} | |
*/ | |
// 第二种方式 | |
state = {name:'Asuhe'} | |
//render 函数必须要有 | |
render(){ | |
return ( | |
<div> | |
<h2>{this.state.name}</h2> | |
</div> | |
) | |
} | |
} |
# props
props
属性是用来接收外部传给组件的数据的,如果我们直接在标签上写数据, props
会自动接收该数据。
ReactDOM.render(<MyComponent age={18} />,document.querySelector('#root')) |
# 限制 props 的数据类型
有时候我们希望限制传入数据的类型,此时我们需要额外加载一个 prop-types.js
包,里面有 PropTyps
对象以供我们使用。示例代码如下:
// 需求: | |
// 1.name 属性必须为 string,age 属性必须为 number,sex 属性必须为 string | |
// 2.sex 属性必须传入 | |
// 3.sex 若未传入则默认值为 male | |
class Person extends React.Component { | |
static propTypes = { | |
name: PropTypes.string, | |
age: PropTypes.number, | |
//sex 为必须 | |
sex: PropTypes.string.isRequired | |
} | |
// 设置默认 props 值 | |
static defaultProps = { | |
sex: 'male' | |
} | |
render() { | |
return ( | |
<ul> | |
<li>name:{this.props.name}</li> | |
<li>age:{this.props.age}</li> | |
<li>sex:{this.props.sex}</li> | |
</ul> | |
) | |
} | |
} | |
let data = { | |
name: 'asuhe', | |
age: 22, | |
// sex: 'male' | |
} | |
ReactDOM.render(<Person {...data} />, el) |
# refs
当我们需要获取标签 or 组件实例时,可以使用 ref
标记。然后就可以在函数中利用 this.refs
找到该组件 or 标签。 ref
有三种形式分别是:字符串类型、回调函数类型和 refs
对象类型。
# 字符串类型的 ref
字符串形式的 ref 已经不推荐使用, ref 会被自动收录进组件的 refs 里,如同 props。
class Person extends React.Component { | |
showData = (event) => { | |
event.preventDefault() | |
let { input2: { value } } = this.refs | |
console.log(value) | |
} | |
render() { | |
return ( | |
<form> | |
<input ref="input1" type="text" placehoder="username" /> | |
<button onClick={this.showData}>提交</button> | |
<input ref="input2" type="password" placehoder="password" /> | |
</form> | |
) | |
} | |
} | |
ReactDOM.render(<Person />, el) |
# 回调函数类型的 ref
回调函数形式的 ref 会将该标签 DOM 传给回调函数的形参,用 this 接住挂载在组件实例上。
class Person extends React.Component { | |
showData = (event) => { | |
event.preventDefault() | |
let { input2: { value } } = this | |
console.log(value) | |
} | |
render() { | |
return ( | |
<form> | |
<input ref={a => this.input1 = a} type="text" placehoder="username" /> | |
<button onClick={this.showData}>提交</button> | |
<input ref={b => this.input2 = b} type="password" placehoder="password" /> | |
</form> | |
) | |
} | |
} | |
ReactDOM.render(<Person />, el) |
# refs 对象类型的 ref
使用自定义 ref 对象 ref 对象内含 {current: 被 ref 标记的标签实例} 当多个标签使用同一个 ref 对象标记时,仅保留最后一个。
class Person extends React.Component { | |
// 若要 ref 标记多个标签实例,则需要声明多个属性创建多个 React.createRef | |
myRefs = React.createRef() | |
showData = (event) => { | |
event.preventDefault() | |
let { current: { value } } = this.myRefs | |
console.log(value) | |
} | |
render() { | |
return ( | |
<form> | |
<input ref={this.myRefs} type="text" placehoder="username" /> | |
<button onClick={this.showData}>提交</button> | |
<input ref={this.myRefs} type="password" placehoder="password" /> | |
</form> | |
) | |
} | |
} | |
ReactDOM.render(<Person />, el) |