状态和生命周期
组件转换为一个类
类即包含有自己特定的功能
如一个Clock组件转换为Clock类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Clock(props){
return (
<h1>time is : {props.date.toLocaleTimeString()}</h1>
);
}
function tick(){
ReactDOM.render(
<Clock date = {new Date()}/>, //需要传入参数date
document.getElementById('root')
)
}
setInterval(tick, 1000);
转换为类并加上生命周期 componentDidMount()为每次组件内render()插入DOM完成后,加载一次 componentWillUnmount()为组件移除DOM之前执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Clock extends React.Component{
constructor(props){
super(props);
this.state = {date : new Date()};
}
componentDidMount() { //给该类加上生命周期
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() { //给该类加上生命周期
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render(){
return (
<h1>time is : {this.state.date.toLocaleTimeString()}</h1>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
)
分为5个步骤:
-
通过ReactDOM.render()调用Clock的construtor;当Clock需要显示当前时间的时候,它带着Date对象将this.state进行初始化。稍后对this.state进行更新。
- Clock调用construtor之后,调用render()方法。该render()使React渲染出DOM。
- 当Clock插入DOM结束后,会调用componentDidMount()生命周期方法,在此方法里,会请求浏览器调用定时器(setInterval),该定时器每秒调用tick()方法一次
- 每秒浏览器调用tick()方法时,组件中的state状态被tick()方法中的setState()改变了,为创建一个Date对象。setState()调用后,会调用shouldComponentUpdate判断是否需要重新render(),此时的this.state.date已经与之前不同了
- 如果之后Clock组件从DOM中被移除了,则会执行componentWillUnmount(),终止tick()中的setInterval()计时器。
控制事件
React的事件与DOM事件类似,只有一些小差别,事件名为小驼峰写法onclick为onClick
1
2
3
4
//DOM Handling events
<button onclick="activateLasers()"/>
//React
<button onClick={activateLasers}/>
在class中,如果需要注册一个事件,则需要将该事件与class进行绑定,如下例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Button extends React.Component {
constructor(){
super();
this.name = "Bob"; //this指Button
this.click3 = this.click2.bind(this);
this.click1 = () => {
console.log(`hello ${this.name}`);
}
}
click2(){
console.log(`hello ${this.name}`); //this指click2
}
render(){
return (
<raw>
<button onClick={this.click1}>Click1</button>
<button onClick={this.click2}>Click2</button>
<button onClick={this.click3}>Click3</button>
<button onClick={(e) => this.click2(e)}>Click3</button>
</raw>
);
}
}
// 此时click2的this非彼this,因为在click2中的this指的是click2
// click3中的this.click2.bind(this)指将class Button中的click2绑定给了class,即向上绑定
// 推荐使用click3的写法
条件渲染
根据条件可以渲染不同的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) { // 根据 isLoggenIn 渲染不同的问候语
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// 你可以尝试设置 isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
可以使用?和:简化运算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: false
};
}
render() {
const { isLoggedIn } = this.state;
const button = isLoggedIn ?
<button onClick={() => { this.setState({isLoggedIn: false}); }}>注销</button>
: <button onClick={() => { this.setState({isLoggedIn: true}); }}>登录</button>;
return (
<div>
<h1>
{
isLoggedIn ? 'Welcome back!' : 'Please sign up.'
}
</h1>
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
如果在某些条件下不需要渲染,return null即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
ReactDOM.render(
<WarningBanner warn={true} />, //尝试一下false,此时返回null
document.getElementById('root')
);