持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第33天,点击查看活动详情
类组件,比函数组件更实用,可以写异步啊,有很多钩子函数可以调用啊,功能非常丰富。
但其实,类 和 函数 本质都一样。
类组件
//继承之后自己成为了组件
class Welcome extends React.Component {
render() {
console.log(this);//已经当前组件实例
console.log(this.props);//直接使用props,react自动挂载
return <h1>hello{this.props.name}</h1>
}
}
const e = <Welcome name="jack" /> //相当于实例
console.log(e, "e");//是一个函数
ReactDOM.render(e, document.getElementById("app"))
复制代码
由图可知,react会自动将props挂载到类的this实例中,也就是用this可以获取到props。
所以可以直接用this.props打印出实例中的对象name="jack"
constructor()
在普通类中都有constructor构造函数指向类,类组件中也是如此。
同样,也有super继承父组件的方法可以使用。
constructor(props) {
super(props);/等同于/this.props = props
//super(), this.props=undefined
console.log(props); //name:"jack",打印的就是constructor的参数props
}
复制代码
当super继承了父元素的props后,在构造函数中可以直接调用props中的关键字/对象.
对比
类组件与函数组件有什么差别吗?
为什么要做类组件?因为有很多react父类继承给子类的函数,需要很多钩子去调用,并且在钩子中可以自己维护状态。
当用时钟的案例时,就可以看出差异。
用函数组件写时钟时,是通过每次重新获取props中改变time的值重新渲染来构成时钟。
而class,则是可以通过挂载在实例上的方法,及钩子函数,来自动自然改变时钟的值。
class中的实现
定义好时间
class Clock extends React.Component {
constructor(props){
super(props)
this.state={time:new Date().toLocaleTimeString()}
}
//state写法2,直接写成对象的形式
//state={}
}
复制代码
组件渲染:
render() {
console.log(""render)
return (
<div>
<h1>Clock</h1>
<h1>time:{this.state.time}</h1>
</div>
)
}
复制代码
新钩子函数:componentDidMount()会在第一次渲染完毕后执行
componentDidMount() {
console.log("componentDidMound"); //执行一次
setInterval(() => {
//执行方法,改变状态时间。=》重新渲染 =》更新时间
this.state={time:new Date().toLocaleTimeString() }//直接改变状态赋值成功,render不执行
console.log(this.state.time,"之后的time");//可以获得
}, 1000)
}
复制代码
设置了定时器,使其每隔一秒重新获得时间,并且赋值给原始state数据。
运行之后可知结果为,页面时间仍然为初始时间,即使有定时器改变值也无法生效,获得的之后的时间也是 初始时间。能改变状态,但render不执行。
于是想到方法 this.forceUpdate()去强制执行render。不改变状态,直接render。
setInterval(() => {
this.state.time = new Date().toLocaleTimeString()
this.forceUpdate()//强制更新
console.log(this.state.time, "之后time");
}, 1000)
复制代码
如图:render也实时更新,界面time也在改变
果然,将该实例上的强制更新函数执行后,成功每秒都改变了页面上的数据。但强制更新,过于暴力。
还有一种实时更新状态,且无需暴力更改。
也是挂载在实例上的方法-------setState({})
它可以默认就改变state中的值。
componentDidMount() {
console.log("componentDidMound"); //执行一次
this.setState({time:new Date().toLocaleTimeString()})
}
复制代码
如上书写,是不是可以成功改变呢?答案成功。又能改变状态,又有能力去重新render
小问题:在setState下打印time值,是否为更新后的值呢?
componentDidMount() {
console.log("componentDidMound"); //执行一次
this.setState({time:new Date().toLocaleTimeString()})
console.log(this.state.time)//更改前的数字,没有被更新。
}
复制代码
答案还是原先的time,这是为什么呢。
明明已经更改了time的值,但是打印时却仍然是没有改变的time,原因之前好像遇到过,那就是异步问题。例如:
state = { n: 1111111 } //初始设置
<h1>time:{this.state.n}</h1> //更改后的数字
this.setState({ n: 222222222222 }) //改变值
console.log(this.state.n, "之后n"); //仍然打印111111111111
复制代码
上面代码更加清晰,初始为1111111,更改为2222222,界面的n更改成功,但输出的n仍为11111111.
原因:打印n语句为同步事件,而setState()执行的为异步方法。
解决这一问题的方法就是 写回调函数,立即执行,使得setState执行之后直接获取改变后的值。
this.setState({
n:22222222
},()=>{
console.log(this.state.n,"callback"); //222222222
})
复制代码
卸载类组件----事件
<button onClick={()=>{ReactDOM.unmountComponentAtNode(document.getElementById("app"))}}>移除组件</button>
复制代码
点击按钮时,就会使得app中的时钟组件瞬间消失。
且在组件卸载之 前 可以调用componentWillUnmount(){}去进行资源释放和清理垃圾。例如清理定时器。
componentWillUnmount(){
clearInterval();
}