持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情
前言
大家好,上一篇文章组件与自定义属性中我们学习了React中的组件和自定义属性props。我们知道react中的组件分为类组件和函数组件,函数组件是一个静态组件,一旦被渲染就不能改变了,除非重新进行渲染。最后还学习了自定义属性props,所有的父组件在调用子组件时,可以通过标签属性的形式给子组件传值,在子组件中则通过props.xxx来获取。今天我们将继续学习react中的state和组件的生命周期。
State
在前面元素渲染一章中我们用函数组件做了一个时钟的例子,由于函数式组件是一个静态组件,内容一旦渲染就不能再改了,除非通过Reactdom.render重新渲染。但仔细想想react这么火爆这么强大不可能设计的这么low。没错,其实react已经为我们准备好了两种更新UI的方式以解决这个问题:一种是React Hooks(后面会学习),另一种也是本章即将学习的一种方式:state。那么state是个什么玩意呢,它又是如何实现更新UI的呢,我们继续往下看。
- 首先State与props类似,但是State是React组件内部定义的一个私有属性,并且完全受控于当前组件
- 在定义组件时,把需要用到的一些属性定义在State对象中,然后通过this.state.[属性名]来访问该属性
- State 一般都只定义在类组件中,因为类组件都会继承自React.Component,而这个类中有个setState方法,我们可以通过调用setState方法来更新类组件中的state属性进而更新页面内容
- 在组件中定义state属性时,只能命名为“state”,这样才能通过setState方法来更新state属性,因为在setState方法中默认会寻找名为state的属性并进行处理,所以如果命名为其它名称,是无法通过setState来更新属性值及DOM内容的
接下来我们把前面时钟案例中的函数组件改造为类组件
class Clock extends ReactComponent{
constructor(){
this.state = {
date: new Date().toLocaleTimeString()
}
}
render(){
return <h1>{this.state.date}</h1>
}
}
ReactDOM.render(<Clock />,document.getElementById('root'));
如上代码,我们把函数组件转换成了类组件,同样实现了一个时钟案例,只不过目前还是静态的,时间还不会自动更新。接下来我们继续来完善这个Clock组件,设置定时器并每秒更新它。
在类组件中使用生命周期方法
- 分析与思考 上面的代码中,我们已经实现了一个静态的时钟组件,那我们发现当页面第一次加载的时候,显示出来的时间就是当前时间,但是这个时间却是固定不变的,这显然不是我们想要的效果。那么我们应该想办法让时钟走起来。 试想当页面第一次渲染加载完成的时候,页面上显示的时间是正确的,那么如果我们在页面第一次加载完成后能够自动执行一个方法并设置一个计时器,来让时钟走起来是不是就可以了呢?
另外如果上面的想法可行,我们在页面第一次加载后设置了定时器,那么在页面卸载前我们还应该手动清除定时器,因为我们知道,如果定时器不手动清除的话就有可能会一直存在,从而影响程序的性能,甚至可能导致内存泄漏。那么这就需要在页面卸载完成前也得自动调用一个函数来执行这些操作。
其实React还真为我们提供了一套这样的方法,这类方法在React中被称为“生命周期方法”。
接下来,我们就按照我们的想法来使用一下这些生命周期方法
- componentDidMount 第一个方法componentDidMount,这个方法会在组件第一次渲染完成后执行,所以我们可以把定时器放在这个方法里面。因为后面组件被卸载时我们还需要清除定时器,所以在设置定时器时还需要把计时器返回的ID保留下来,便于后面清除使用。 首先在componentDidMount中我们给组件添加一个timer属性,然后把计时器返回的ID保存在timer中
componentDidMount(){
this.timer = setInterval(
() => {
//这里写更新时间的逻辑
},1000);
}
- componentWillUnmount 第二个方法componentWillUnmount,光从名称上看我们应该也知道这个方法是干嘛的了,该方法将会在组件被卸载之前执行,所以我们可以清除计时器的代码写在这里
componentWillUnmount(){
clearInterval(this.timer);
}
组件的第一次渲染和卸载前的动作我们已经借助两个生命周期函数实现了,接下来就是定义一个方法让时钟真正的转起来。
- 首先我们再在类组件中定义一个tick方法,用于更新组件的state从而更新页面时钟
- 然后在tick方法中我们通过调用setState方法来更新state中的date值
需要注意的是:这里不能直接通过this.state.date = xxx来修改date值,因为这样即使date值被修改了,页面也不会重新渲染。 只有通过调用setState方法改变date,页面才会重新渲染。因为setState不仅能够修改state中的值,同时还能触发DOM的更新让组件重新渲染。
tick(){
this.setState({
date:new Date().toLocaleTimeString()
});
}
下面我们把所有代码进行整合,来完成我们的时钟小案例
class Clock extends ReactComponent{
constructor(){
this.state = {
date: new Date().toLocaleTimeString()
}
}
render(){
return <h1>{this.state.date}</h1>
}
componentDidMount(){
this.timer = setInterval(
() => {
this.tick();
},1000);
}
componentWillUnmount(){
clearInterval(this.timer);
}
tick(){
this.setState({
date:new Date().toLocaleTimeString()
});
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
使用State的注意事项
上面我们已经通过时钟小案例掌握了state和生命周期方法的一些基本使用。下面我们再来说一下state在使用的时候有哪些需要注意的事项
- 不要直接修改State 上面已经提到过,我们不能直接通过this.state.xxx = xxx来修改state,这种修改即使state的值变了,组件也不会被重新渲染
- 若要给state属性赋值,只能在构造函数(constructor)中给this.state属性赋值
- 而要想修改state的值,我们应该通过调用setState方法来修改
this.state.name = "hello";//错误的写法
this.setState({name:'Alvin'});//正确的写法
constructor(){
this.state = {name:'Yinnes'};//正确的写法
}
总结
本次分享我们学习了react中的新的知识点state以及两个生命周期函数componentDidMount和componentWillUnmount,通过这两个新的知识点我前面的时钟组件进行了改造,将原来的重新渲染组件实现时钟的转动改造为通过state修改数据实现时钟的转动。好了本次分享就到这里了。