React官网经典代码【计时器】的详解注释

本文详细解读React官网计时器组件的代码,涉及箭头函数的作用、setInterval的使用以及this.timerID的理解。通过实例解析,展示了箭头函数如何解决this绑定问题,以及如何实现每秒更新组件状态的功能。
摘要由CSDN通过智能技术生成

先看 React 官网代码:

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 (
      <div>
        <h1>Hello, world!</h1>
        <h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

第一个问题:怎么理解() => this.tick()
这是ES6中声明函数的一种方式,叫做箭头函数表达式。
ES6是指ECMAScript6。
为什么引入箭头函数(Arrow Function)?
有两个方面的作用:
第一、这是更简短的函数。
第二、不用绑定this。
箭头函数有两种书写格式。

箭头函数的第一种书写格式
以前写函数的方式是:

function(x){
  return x*x;
}

换成箭头函数,就写成:

x => x*x

箭头函数的第二种书写格式
以前写函数的方式是:

function(x){
  if(x>0){
    retun x*x;
  }
  else{
    retun - x*x;
  }
}

用箭头表达式来写,就是下面的形式:

x => {
    if (x > 0) {
        return x * x;
    }
    else {
        return - x * x;
    }
}

参数不是一个箭头函数的书写方式
// 无参数:

() => 3.14

// 两个参数:

(x, y) => x * x + y * y

// 可变参数:

(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}

返回值是对象的箭头函数的书写方式
//这么写是不对的

x => { foo: x }

//这么写是对的

x => ({ foo: x })

箭头函数是修正了this使用过程中的错误
javascript中有一个错误,就是函数对于this绑定的错误处理。
可以看下面的例子:

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = function () {
            return new Date().getFullYear() - this.birth; // this指向window或undefined
        };
        return fn();
    }
};

上面的例子中,使用this,就有问题。
第一个this,是外部函数中this还能够使用对象。
第二个this,内部函数中this已经指向不到对象了。
下面的例子中,使用箭头函数,就没有问题。

var obj = {
    birth: 1990,
    getAge: function () {
        var b = this.birth; // 1990
        var fn = () => new Date().getFullYear() - this.birth; // this指向obj对象
        return fn();
    }
};
obj.getAge(); // 25

用官方的说法是:箭头函数就是为了确定this的词法作用域。
这种绑定,让你即便使用call()、apply()调用箭头函数的时候,也没有办法改变this的绑定。
如下所示:

var obj = {
    birth: 1990,
    getAge: function (year) {
        var b = this.birth; // 1990
        var fn = (y) => y - this.birth; // this.birth仍是1990
        return fn.call({birth:2000}, year);
    }
};
obj.getAge(2015); // 25

() => this.tick()的理解
这是一个没有参数的函数。返回的是this.tick()。
这里的this当然指的就是组件对象。
this.tick()就是组件的tick()方法。

  tick() {
    this.setState({
      date: new Date()
    });
  }

tick()方法当中修改了组件的state状态。
是用一个对象{date:new Date()}修改了state的状态。
tick()方法返回的就是这个对象。
这个对象有一个date属性,值是new Date()。

() => this.tick()

如果用常规的方法来写,是这样子的:

let that = this;
this.timerID = setInterval(function(){
   return that.tick(); 
},1000)

第二个问题:setInterval()函数是怎么用的?
setInterval()的主要作用是:周期地调用并执行一个函数。
基本的语法,是这样的:

setInterval(函数名,执行周期)
在这里例子当中,

this.timerID = setInterval(
() => this.tick(),
1000
);

表示的就是1秒钟就要调用一次this.tick()这个函数。
详情我是参考的这篇文章

第三个问题:this.timerID是怎么理解的?
这个涉及到javascript当中对象属性的添加问题。
这个有两种方法:
这里,我是参考这篇文章理解的。

动态对象

//创建obj对象
var obj = new Object();
//为对象添加动态属性
obj.userName = "admin";
obj.passWord = "123456";
//输出
console.log(obj);

删除对象属性

//创建obj动态对象
var obj = new Object();
//为对象添加动态属性
obj.userName = "admin";
obj.passWord = "123456";    
//移除属性
delete obj.passWord;
console.log(obj);

固定对象

//创建固定对象
var dt = {userName:"admin",password:"123456"};
console.log(dt);

小结
这段代码,到这里,是基本上可以理解了。

//声明了一个组件类叫做Clock,继承自React.Component
class Clock extends React.Component {
  
  //这是组件类的构造函数,里面初始化了组件的状态state。
  //这是挂载时候,执行的生命周期方法的第一个。
  constructor(props) {
    super(props);
    this.state = {date: new Date()};//初始化了组件的状态state。
  }
 
 //这是组件挂载的生命周期函数,表示组件执行挂载的方法。
 //代码是重写了这个方法,表示在挂载的时候,设置了一个定时器。
 //组件类是一个动态对象,所以this.timerID表示是一个定时属性。
 //这个属性是一个setInterval函数,每1秒执行一个函数,就是tick()
 //采用()=>this.tick()是因为要限定this的词法作用域
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
 
  //这是组件的卸载方法。
  //代码重写了这个方法,然后在卸载的时候,清除定时器。
  //清除定时器,采用的方法,就是clearInterval()方法。 
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
 
  //这是自定义的组件类方法。
  //方法内是更新设置了组件的状态。
  //组件的状态是一个属性。属性的值是一个对象。
  //对象也有一个属性,属性的值也是一个对象。
  //所以这里是this.state这是属性的值。
  //this.state.date这个是属性的值对象的值。
  //通过this.state.date才能够调用到new Date()。
  tick() {
    this.setState({
      date: new Date()
    });
  }
 
  //一个组件类是必须要实现一个render()方法的。
  //这个render()方法是要返回一个JSX元素的。
  //这里返回**一个**元素,不是多个元素。
  //返回一个块元素,可以包含多个子元素。
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

//上面定义了一个组件类Clock
//类就是模板。
//我们的目的是把组件类插入到HTML DOM的节点当中。
//所以,要用ReactDOM.render()方法。 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);

这段代码的执行顺序,是这样的:

当 被传递给 ReactDOM.render() 时,React 调用 Clock 组件的构造函数。 由于 Clock 需要显示当前时间,所以使用包含当前时间的对象来初始化 this.state 。 我们稍后会更新此状态。

React 然后调用 Clock 组件的 render() 方法。这是 React 了解屏幕上应该显示什么内容,然后 React 更新 DOM 以匹配 Clock 的渲染输出。

当 Clock 的输出插入到 DOM 中时,React 调用 componentDidMount() 生命周期钩子。 在其中,Clock 组件要求浏览器设置一个定时器,每秒钟调用一次 tick()。

浏览器每秒钟调用 tick() 方法。 在其中,Clock 组件通过调用 setState() 来调度UI更新。 通过调用 setState() ,React 知道状态已经改变,并再次调用 render() 方法来确定屏幕上应当显示什么。 这一次,render() 方法中的 this.state.date 将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。

一旦 Clock 组件被从 DOM 中移除,React 会调用 componentWillUnmount() 这个钩子函数,定时器也就会被清除。

参考:https://www.cnblogs.com/gnuzsx/p/11924960.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值