react class/hooks + typescript 实现一个定时器的功能遇到的坑点

今天我们来看下react中如何实现定时器调用的功能!
下面实现的是日期实时更新的效果,看起来比较简单,我们现在用不同的方式来实现这种效果

在这里插入图片描述
react&&class&&js组件

import React, { Component } from "react";

export default class Clock extends Component {
  constructor(props) {
    super(props);
    this.state = {
      time: new Date(+new Date() + 8 * 3600 * 1000)
        .toISOString()
        .replace(/T/g, " ")
        .replace(/\.[\d]{3}Z/, "")
    };
  }
  componentWillMount() {
    this.timer = setInterval(() => {
      this.setState({
        time: new Date(+new Date() + 8 * 3600 * 1000)
          .toISOString()
          .replace(/T/g, " ")
          .replace(/\.[\d]{3}Z/, "")
      });
    });
  }
  componentWillUnmount() {
  //卸载的时候清除掉定时器,释放内存
    clearInterval(this.timer);
  }
  render() {
    const { time } = this.state;
    return (
      <div>
        <h2>{time}</h2>
      </div>
    );
  }
}

react&&class&&ts
起初觉得实现起来跟在js中差不多,但是实现过程遇到了一些坑点,比较让人摸不着头脑,特此记录下!

1.关于propType,StateType的类型约束
不加类型约束,直接爆红,所以此处必须加上我们预传递的props,state
在这里插入图片描述

在这里插入图片描述
2. constructor(props:any)
props后面的类型约束也不能省略,即使不知道我们就设为any即可解决红波浪线
在这里插入图片描述
3.下面是实现的反例,会报错

import React, { Component } from 'react'

type StateType = {
    time: string,
};
type propType = {
    
};
export default class Timer extends Component<propType,StateType> {
    constructor(props:any) {
        super(props)
        this.state = {
            time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, ''),
         }
    }
    componentWillMount() {
         this.inter = window.setInterval(() => {
            this.setState({
                time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
            })
        },1000)
    }
    componentWillUnmount() {
        clearTimeout(this.inter)
    }
    render() {
        console.log(this.state.time)
        const { time } = this.state
        return <div>3333
            <h2>{ time }</h2>
        </div>
    }
}

像在js的class中那样,我们定义interval的返回值,代码会爆红,
在这里插入图片描述
js中的思维,我们一般会设置一个null来定义定时器的返回
但是ts中不行的,这里的坑困扰了很久,查资料研究发现
我们在js中
在这里插入图片描述

直接写setInterval()是用node的定时器,那么我们只需要 window.setInterval() 这样子调用就能用浏览器自带定时器
在这里插入图片描述
于是尝试着下面这样写,在运行就可以正常显示实时的时间
在这里插入图片描述
还是按照js的思维,也是行不通
在这里插入图片描述
最后按照react的修改值只能用setState方法的思维,最终实现了效果
完整的代码

import React, { Component } from 'react'
type StateType = {
    time: string,
    inter: number
};
type propType = {
    
};
export default class Timer extends Component<propType,StateType> {
    constructor(props:any) {
        super(props)
        this.state = {
            time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, ''),
            inter:0
         }
    }
    componentWillMount() {
        /* this.inter = window.setInterval(() => {
            this.setState({
                time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
            })
        },1000) */
        this.setState({
        //主要此处的赋值必须是这样,暂时不知道还有没有别的实现方式
        //两层嵌套的setState,看着有点怪异
            inter: window.setInterval(() => { 
                this.setState({
                    time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
                })
            })
        })
    }
    componentWillUnmount() {
        clearTimeout(this.state.inter)
    }
    render() {
        console.log(this.state.time)
        const { time } = this.state
        return <div>
            <h2>{ time }</h2>
        </div>
    }
}

react&&hooks&&js
实现的比较顺利

import React, { useState, useEffect } from "react";

function Clock() {
  const [time, setTime] = useState(
    new Date(+new Date() + 8 * 3600 * 1000)
      .toISOString()
      .replace(/T/g, " ")
      .replace(/\.[\d]{3}Z/, "")
  );
  //处理副作用部分
  useEffect(() => {
    //定义定时器的引用
    const timer = setInterval(() => {
      setTime(
        new Date(+new Date() + 8 * 3600 * 1000)
          .toISOString()
          .replace(/T/g, " ")
          .replace(/\.[\d]{3}Z/, "")
      );
    }, 1000);
    return () => {
      //组件销毁时清除定时器引用
      clearInterval(timer);
    };
    // [] 为空说明需要一直执行,没有依赖,有值的情况下是依赖值变化了才会执行到effect副作用
  }, []);
  return <div>{time}</div>;
}

export default Clock;

react&&hook&&ts

 import React, { useState, useEffect } from "react";
function Clock() {
  const [time, setTime] = useState(
    new Date(+new Date() + 8 * 3600 * 1000)
      .toISOString()
      .replace(/T/g, " ")
      .replace(/\.[\d]{3}Z/, "")
  );
  //处理副作用部分
  useEffect(() => {
    //定义定时器的引用,需要区分是nodejs的定时器还是浏览器的定时器
    const timer:number = window.setInterval(() => {
      setTime(
        new Date(+new Date() + 8 * 3600 * 1000)
          .toISOString()
          .replace(/T/g, " ")
          .replace(/\.[\d]{3}Z/, "")
      );
    }, 1000);
    return () => {
      //组件销毁时清除定时器引用
      clearInterval(timer);
    };
    // [] 为空说明需要一直执行,没有依赖,有值的情况下是依赖值变化了才会执行到effect副作用
  }, []);
  return <div>{time}</div>;
}

export default Clock;

在这里插入图片描述
一个小小的定时器功能,在ts中会遇到这样的坑点,惯性思维真的会害人!打完收工~~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值