React组件
React Component组件
React组件有两类: "函数"组件和"类"组件.
重要说明:
-
在组件中如何使用构造函数
constructor
与super
.(参考链接)- 在constructor中使用this, 必须添加super().
- 在constructor中使用this.props, 必须添加super(props).
- 使用场景一: 要在构造函数里初始化组件的state
- 使用场景二: 要在构造函数中,绑定组件交互事件的this到组件实例上.
-
组件名首字母必须大写, 且每个组件只能有一个根节点(容器).
eg:
import React, {Component} from 'react'
function Greeting() {
return <h1>hello world!</h1>
}
class Welcome extends Component{
render() {
return <h1>hello, world</h1>
}
}
// 注意:el不是组件
const el = (
<div>
<Greeting />
<Welcome />
</div>
);
//use1
ReactDOM.render(
el,
document.getElementById('root')
);
//不能省略div标签
function App() {
return (
<div>
<Greeting />
<Welcome />
</div>
)
}
//use2
ReactDOM.render(
<App />,
document.getElementById('test')
);
组件间通信
规则: props down, events up. 对于某个组件来说它的props属性是只读的, 只能通过通知其父组件, 由父组件的某个方法执行修改操作.
eg:
class Clock extends Component {
constructor(props) {
super(props);
this.state = {
date: new Date()
};
}
componentDidMount() {
this.timer = setInterval(
() => this.tick(),
1000
);
}
componentWillUnMount() {
clearInterval(this.timer);
}
//父组件传递的数据修改时触发
componentWillReceiveProps(nextProps) {
if (nextProps.enable) {
console.log('用户开启了时钟');
} else {
console.log('用户停止了时钟');
}
}
//组件的方法
tick() {
if (this.props.enable) {
this.setState({
date: new Date()
})
}
}
render() {
return (
<div>
<p>
<span>now Time: </span>
{this.state.date.toLocaleTimeString()}
</p>
</div>
)
}
}
class ToggleButton extends Component {
handleClick() {
//调用父组件在props中提供的onToggleText方法
this.props.onToggleText();
}
render() {
return (
<button onClick={ () => this.handleClick() }>
{this.props.text}
</button>
)
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
clockEnable: true
};
}
//该方法注册后, 由子组件调用, 用于修改时钟的开关状态
toggleClock() {
let clockEnable = !this.state.clockEnable;
this.setState({
clockEnable: clockEnable
});
}
render() {
return (
<div className="App">
<Clock enable={this.state.clockEnable}></Clock>
<ToggleButton text={this.state.clockEnable ? '停止时钟' : '开启时钟'} onToggleText={ () => this.toggleClock() }></ToggleButton>
</div>
);
}
}
处理组件的交互事件(鼠标点击事件, 用户触摸事件等)
React组件的定义遵循常规ES6 class, 组件的方法并未自动绑定this到class类的实例中.看下面的例子.
eg1:
class Button1 extends Component {
constructor(props) {
super(props);
this.state = {
status: true
};
}
//e为点击事件的event对象
handleClick(e) {
//默认this指向全局对象而不是该组件的实例对象
this.setState({
status: false
});
}
render() {
return (
<div>
//比较<button onClick={ (e) => this.handleClick(e) }>
<button onClick={ this.handleClick }>
{this.state.status ? '未点击' : '已点击'}
</button>
</div>
)
}
}
对两种绑定方式的说明:
未绑定this时
-
<button onClick={ this.handleClick }>
等同于><button onClick={ function() { //do sth.} }>
, 匿名函数function内部的this默认指向全局对象, 在浏览器中为window
对象. -
<button onClick={ (e) => this.handleClick(e) }>
因为箭头函数没有自己的this, 内部的this指向外部的this, 也就是组件实例.(也可以理解为函数创建时的this,而不函数调用时的this)
要使用第一种方法, 需要在constructor
函数中修改该方法中的this指向.
//...
constructor (props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
//...
组件的生命周期
详情请查看:各生命周期详解.
需要注意的是, 是否使用ES6语法, 书写class组件的方式是不同的(参见React官方文档).
组件作用域
在多个组件组合使用场景下:
在父子组件关系中, 子组件无法直接访问到父组件的变量, 父组件的数据只能通过props传递到子组件.
eg:
function Test(props) {
return (
<h1>my test: { props.aa }</h1>
)
}
class App extends Component {
render() {
const aa = 'test string';
return (
<div>
This is just a test
<Test test={aa}>
//仍属于Test的父组件作用域范围
{ aa }
</Test>
</div>
)
}
}
行为影响状态,状态影响视图