react-component-class

95 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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不执行。

image.png

于是想到方法 this.forceUpdate()去强制执行render。不改变状态,直接render。

  setInterval(() => {
                    this.state.time = new Date().toLocaleTimeString()
                    this.forceUpdate()//强制更新
                    console.log(this.state.time, "之后time");
                }, 1000)
复制代码

如图:render也实时更新,界面time也在改变

image.png

果然,将该实例上的强制更新函数执行后,成功每秒都改变了页面上的数据。但强制更新,过于暴力。

还有一种实时更新状态,且无需暴力更改。

也是挂载在实例上的方法-------setState({})

它可以默认就改变state中的值。

 componentDidMount() {
                console.log("componentDidMound"); //执行一次
              this.setState({time:new Date().toLocaleTimeString()})
}
复制代码

如上书写,是不是可以成功改变呢?答案成功。又能改变状态,又有能力去重新render

image.png

小问题:在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();
}