react hooks 封装一个countDown 倒计时组件

news2024/10/7 18:32:24

开发技术

react , hooks , ts , taro

需求分析

需要一个可以按天,时,分和秒来进行倒计时的组件。

简单使用

  • 注:主要逻辑请看 useCountDown
import CountDown from '@/components/countDown';
import { useEffect, useState } from 'react';
import Taro from '@tarojs/taro';

const curTime = Date.now()

export default () => {const [createTime, setCreateTime] = useState<number>(0);useEffect(() => {setTimeout(() => {// 假设:异步获取五分钟前创建的日期setCreateTime(Date.now() - 5 * 60_000)}, 1000)}, [])return (<>{/* 倒计时10秒 */}<CountDown value={curTime} total={10_000} onChange={v => {if(v <= 0) Taro.showToast({title: '到时间了', icon: 'none'})}} />{/* 倒计时3天 */}<CountDown value={curTime} total={3 * 86400_000} />{/* 异步获取五分钟前创建的日期 */}<CountDown value={createTime} total={50 * 60_000} /></>)
} 

countDown组件的封装

props 传参很简单,只有一个 value 起始时间 , 一个 total 倒计时总时间,还有一个 onChange 返回当前的倒计时剩余时间,当为0的时候就可以进行业务需要的倒计时为0的操作了。

import useCountDown from '@/hooks/useCountDown';
import { formatRemainTime } from '@/utils/format';
import { Text } from '@tarojs/components'
import { useEffect } from 'react';
import './index.less';

type PropsType = { /** 起始时间 如果不传就是现在的时间 */value?: number/** 倒计时时间,默认40min */total?: numberonChange?: (val: number) => void
}

export default ({value, total = 2400_000, onChange}: PropsType) => {// 倒计时const [countDownNum, setCountDown] = useCountDown()useEffect(() => {if(value !== void 0) {setCountDown(value, total)}}, [value])useEffect(() => {if(countDownNum !== void 0) {onChange?.(countDownNum)}}, [countDownNum])return (<Text className='com-count-down'>{formatRemainTime(countDownNum)}</Text>)
} 

useCountDown 的封装

首先定义一个计时器变量 timerRef 主要是用于保存/清除计时器;定义一个用来保存一个当前时间的 state;最后再定义一个参数保存值。

const timerRef = useRef<NodeJS.Timer | undefined>()
const [time, setTime] = useState<number>()
const params = useRef({beginTime: 0,total: 0
}) 

当调用 setCountDown 函数时,开启计时器倒计时,同时需要保存一份函数的参数。

// 开启计时器的函数, beginTime: 输入的初始时间 total: 需要计算的时间
const setCountDown = (beginTime: number, total: number) => {params.current = { beginTime, total }clearInterval(timerRef.current)_setInterval(beginTime, total)
} 

开启计时器,根据传入的开始时间,倒计时总时间和当前时间来计算出,当前倒计时的剩余值,如果该值大于0,则表示还有时间可以倒计时。采用 setInterval 每隔一秒触发一次 setTime ,当时间小于0清除计时器即可。

const _setInterval = (beginTime: number, total: number) => {if(!beginTime || !total) returnconst interval = beginTime + total - Date.now()if(interval < 0) returnsetTime(interval)timerRef.current = setInterval(() => {setTime(t => {const _t = t! - 1000if(_t <= 0) {clearInterval(timerRef.current)return 0}return _t})}, 1000);
} 
  • 注意一:销毁组件时,记得清除计时器防止内存泄漏
useEffect(() => {return () => {clearInterval(timerRef.current)}
}, []) 
  • 注意二:由于我这里是用在小程序端的,当小程序退到后台隔几秒后,计时器会自动被停掉,所以当小程序重新展示出来时需要重新开始一下计时器。
useDidShow(() => {clearInterval(timerRef.current)_setInterval(params.current.beginTime, params.current.total)
}) 

useCountDown 完整代码

import { useEffect, useRef, useState } from "react"
import { useDidShow } from "@tarojs/taro"

/** 倒计时钩子 */
const useCountDown = () => {const timerRef = useRef<NodeJS.Timer | undefined>()const [time, setTime] = useState<number>()const params = useRef({beginTime: 0,total: 0})// 退到后台,大约过个六七秒后定时器会自动暂停掉(回来后自动继续之前的定时器),所以会导致时间不准确useDidShow(() => {clearInterval(timerRef.current)_setInterval(params.current.beginTime, params.current.total)})useEffect(() => {return () => {clearInterval(timerRef.current)}}, [])// 开启计时器的函数, beginTime: 输入的初始时间 total: 需要计算的时间const setCountDown = (beginTime: number, total: number) => {params.current = { beginTime, total }clearInterval(timerRef.current)_setInterval(beginTime, total)}const _setInterval = (beginTime: number, total: number) => {if(!beginTime || !total) returnconst interval = beginTime + total - Date.now()if(interval < 0) returnsetTime(interval)timerRef.current = setInterval(() => {setTime(t => {const _t = t! - 1000if(_t <= 0) {clearInterval(timerRef.current)return 0}return _t})}, 1000);}// 手动清除计时器const clearCountDownTimer = () => clearInterval(timerRef.current)return [time, setCountDown, clearCountDownTimer] as const
}

export default useCountDown 

formatRemainTime 格式化剩余时间

根据时间需求:天,时,分和秒定义一个对象数组,包含它们的字符串和对应的时间,遍历该对象数组,处理好天,时,分和秒的情况即可,再在数字前适当添加0即可。

/** 格式化剩余时间 */
export function formatRemainTime(time?: number) {// 当初始化时间为 undefined 时返回if(time === void 0) return '0'const addZero = (n: number) => n >= 10 ? n : ('0' + n)const timeArr: {s: string, t: number}[] = [{s: '天', t: 86400},{s: '时', t: 3600},{s: '分', t: 60},{s: '秒', t: 1},]time = Math.ceil(time / 1000) let res = ''for(let i = 0; i < timeArr.length - 1; i++) {const item = timeArr[i]if(time >= item.t) {const tartget = ~~(time / item.t)res += (!i ? tartget : addZero(tartget)) + item.stime %= item.t}}res += addZero(~~(time)) + timeArr.at(-1)!.sreturn res
} 

总结

回看整个倒计时的代码,感觉代码其实是挺简单的,但是我当时实现起来是花了挺长时间的,主要原因还是我当时对 hooks 不太熟悉,现在回看也觉得写得很一般,不是那么的 hooks;相信很多大牛都能写得比我好很多,我这里只是分享一下自己曾经写的一个小组件。大家可以按需修改使用。

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/154241.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

东宝商城项目(二)——flask-script模块、flask-migrate模块和项目日志配置

学习flask-script模块的使用 1、什么是flask-script flask-script是flask的一个扩展模块&#xff0c;Flask-Script的作用是可以通过命令行的形式来操作Flask。 2、安装flask-script pip install flask-script 3、flask-script的使用 例如有这样一种需求&#xff1a; 我们…

李彦宏开年定调“百度式创新”:反馈驱动,坚定技术

今天在百度热搜看到这么一条置顶话题&#xff0c;让我印象深刻&#xff1a;读懂中国经济的信心所在。 站在2023年起点&#xff0c;无论你是阳了、没阳&#xff0c;还是阳康了&#xff0c;之于个人、企业组织&#xff0c;都太需要信心和激励了。 点进去后是一篇来自《人民日报 …

小程序直播加速抢占电商流量先机

临近春节&#xff0c;到了购置年货的时候&#xff0c;相信有不少小伙伴被淘宝、拼多多、抖音等各大平台的直播卖货吸引。近年来&#xff0c;大家逐渐发现视频直播的影响力已经渗透到各行各业&#xff0c;通过直播带来的流量&#xff0c;不少商家赚得盆满钵满。视频直播这块流量…

Autosar MCAL-GPT配置及使用

文章目录前言GPTGptChannelConfigSetGptChannelIdGptChannelModeGptChannelTickFrequencyGptChannelTickValueMaxGptEnableWakeupGptNotificationGptChannelClkSrcRefGptAssignedHwUnitGptConfigurationOfOptApiServicesGptDeinitApiGptEnableDisableNotificationApiGptTimeEla…

系列33 Flow_Model

Introduction 在上一小节中讲到了Latent Variable Model&#xff08;LAM&#xff09;&#xff0c;VAE。其主要思想就是将隐变量扩充为高维连续的分布&#xff0c;来增强模型的表达能力。而LAM模型中的核心困难是计算不出来&#xff0c;因为&#xff0c;而的维度过高算不出来。而…

GAN Step By Step -- Step7 WGAN

GAN Step By Step 心血来潮 GSBS&#xff0c;顾名思义&#xff0c;我希望我自己能够一步一步的学习GAN。GAN 又名 生成对抗网络&#xff0c;是最近几年很热门的一种无监督算法&#xff0c;他能生成出非常逼真的照片&#xff0c;图像甚至视频。GAN是一个图像的全新的领域&#…

2022 OceanBase 年度报告|用技术让海量数据的管理和使用更简单!

尊敬的各位客户、合作伙伴和开发者&#xff1a; 从 2020 年 6 月 1 日 OceanBase 开启商业化至今&#xff0c;我们一起走过了 900 多天。 从 0.5 到 3.x&#xff0c;我们花了近十年时间&#xff0c;而从 3.x 到 4.x 只用了不到两年&#xff0c;这是 OceanBase 和客户、伙伴、…

C++ 开发环境其实挺难搞的(上)

所谓工欲善其事&#xff0c;必先利其器&#xff0c;我将用两节课的内容向大家介绍 C 的开发工具及开发环境的一些知识。 Visual Studio 诞生至今已有 25 年以上的历史&#xff0c;功能强大&#xff0c;用的人非常多&#xff0c;社区的朋友戏称它为宇宙最强大的 IDE&#xff0c…

LeetCode 147. 对链表进行插入排序

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 欢迎来到茶色岛独家岛屿&#xff0c;本期将为大家揭晓LeetCode 147. 对链表进行插入排序&#xff0c;做好准备了么&#xff0c;那么开始吧。 &#x1f332;&#x1f332;&#x1f434;&#x1f434; 一、题目名称 二、…

ECC原理和RocketChip Cache ECC实现

一、ECC原理说明ECC(Error Correcting Code)全称为错误纠正码&#xff0c;用于对存储器的数据进行完整性检查和纠正&#xff0c;主要用在SRAM、DDR、NAND等存储器设备上。ECC可以对数据进行单比特的纠错和多比特的检错&#xff0c;其原理基于汉明码编码而来。下图是ECC编码的主…

如何通过光耦合器连接继电器

如何通过光耦合器连接继电器 介绍 以下文章介绍如何使用隔离方法或通过光耦合器器件驱动继电器。我们将学习三种方法&#xff0c;第一种方法是将继电器直接连接到光耦合器输出引脚&#xff0c;第二种方法是使用外部PNP晶体管&#xff0c;第三种方法是使用外部NPN晶体管。任何…

二十九、Docker (5)

&#x1f33b;&#x1f33b; 目录一、Maven Docker 插件构建 Docker 镜像1.1 maven Docker 插件构建 Docker 镜像入门1.2 maven Docker 插件构建 Docker 镜像&#xff0c;自定义 DockerFile1.3 maven Docker 插件构建并推送镜像到 Docker 私有仓库二、手动发布部署微服务项目到…

类与对象(三):stactic成员、友元、内部类

类与对象&#xff08;三&#xff09;1. 再谈构造函数1.1 构造函数体赋值1.2 初始化列表1.3 explicit关键字2. static成员2.1 概念特性类中成员变量区别&#xff08;普通变量和static变量&#xff09;:普通成员函数和静态成员函数的区别3. 友元友元函数友元类cout打印自定义类型…

24种代码坏味道和重构手法

最近&#xff0c;小李感觉公司女生们看他的眼神不太对劲了&#xff0c;那种笑容好像是充满慈爱的、姨母般的笑容。 作为一名老实本分的程序员&#xff0c;小李不太习惯这种被人过度关注的感觉&#xff0c;他不知道发生了什么。 小李和小王的关系似乎过于亲密&#xff0c;还经…

ZooKeeper 安装

ZooKeeper 安装 1. 下载安装 1、环境准备 ZooKeeper服务器是用Java创建的&#xff0c;它运行在JVM之上。需要安装JDK 7或更高版本。 2、上传 将下载的ZooKeeper放到/opt/ZooKeeper目录下 #上传zookeeper altp put f:/setup/apache-zookeeper-3.5.6-bin.tar.gz #打开 opt目…

(十)devops持续集成开发——jenkins流水线发布一个docker harbor仓库版的后端maven项目

前言 本节内容我们使用jenkins流水线组件发布一个docker环境的后端maven项目&#xff0c;并使用docker的harbor仓库完成镜像的存储&#xff0c;通过拉取harbor仓库中的项目镜像&#xff0c;完成后端项目的发布&#xff0c;关于harbor仓库的搭建&#xff0c;可以参考往期博客内…

Python学习笔记之模块

可迭代对象 概念&#xff1a;更新换代&#xff0c;每次更新都是根据上一次的结果作为基础。 有哪些&#xff1a;字符串&#xff0c;列表&#xff0c;字典&#xff0c;元组&#xff0c;集合&#xff0c;文件对象&#xff0c;特殊函数&#xff08;生成器&#xff09; 迭代器对…

软件测试/测试开发 | AppCrawler 自动遍历测试工具实践(一)

本文为霍格沃兹测试学院学院学员课程学习笔记。 公众号搜索&#xff1a;TestingStudio 霍格沃兹的干货都很硬核 AppCrawler 是由霍格沃兹测试学院校长思寒开源的一个项目&#xff0c;通过名字我们大概也能猜出个方向&#xff0c;Crawler 是爬虫的意思&#xff0c;App 的爬虫&am…

GitHub上标星79K的LeetCode算法小抄开放下载了

在大厂面试中我们不可避免的会考到算法&#xff0c;为什么大厂一定要考察算法呢&#xff1f;因为它包含了太多的逻辑思维&#xff0c;可以考察你思考问题的逻辑和解决问题的能力&#xff1b;这一点也是面试官比较看重的&#xff0c;因为它可以反映出你的潜力&#xff0c;我曾经…

Qt布局管理器(QHBoxLayout,QVBoxLayout)

文章目录布局管理器是什么使用代码添加布局管理器QVBoxLayoutQHBoxLayout使用ui文件添加布局管理器布局管理器的嵌套提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 布局管理器是什么 可以把一些组件按一定的次序排列&#xff0c;这就是布局管理器。 他…