1import { useState, useEffect } from "react";
2
3// 入参是一个时间段,比如6000s,不是具体的过期时间点,因为考虑到用户可能会修改电脑的时间,这样在获取当前时间的时候就会产生误差
4export const CountDown = ({ countDown = 4 }) => {
5 let cd = countDown;
6 let timer = null;
7
8 const [time, setTime] = useState("");
9
10 const handleData = () => {
11 if (cd <= 0) {
12 setTime("到时间啦");
13 return timer && clearTimeout(timer);
14 }
15 const d = parseInt(cd / (24 * 60 * 60) + "");
16 const h = parseInt(((cd / (60 * 60)) % 24) + "");
17 const m = parseInt(((cd / 60) % 60) + "");
18 const s = parseInt((cd % 60) + "");
19 setTime(`倒计时: ${d}天${h}时${m}分${s}秒`);
20 cd--;
21 timer = setTimeout(() => {
22 handleData();
23 }, 1000);
24 };
25
26 useEffect(() => {
27 handleData();
28 return () => {
29 timer && clearTimeout(timer);
30 };
31 }, []);
32
33 return <div>{time}</div>;
34};
35export default CountDown;1import { useState, useEffect, useRef } from "react";
2
3const CountDown = ({ countDown }) => {
4 const cd = useRef(countDown);
5 const timer = useRef(null);
6
7 const [time, setTime] = useState("");
8
9 const dealData = () => {
10 if (cd.current <= 0) {
11 setTime("");
12 return timer.current && clearTimeout(timer.current);
13 }
14 const d = parseInt(cd.current / (24 * 60 * 60) + "");
15 const h = parseInt(((cd.current / (60 * 60)) % 24) + "");
16 const m = parseInt(((cd.current / 60) % 60) + "");
17 const s = parseInt((cd.current % 60) + "");
18 setTime(`倒计时: ${d}天${h}时${m}分${s}秒`);
19 cd.current--;
20 timer.current = setTimeout(() => {
21 dealData();
22 }, 1000);
23 };
24
25 useEffect(() => {
26 dealData();
27 return () => {
28 timer.current && clearTimeout(timer.current);
29 };
30 }, []);
31
32 return <div>{time}</div>;
33};
34
35export default CountDown;1import { useState, useEffect } from "react";
2
3const CountDown = ({ countDown = 5 }) => {
4 let [cd, setCd] = useState(countDown);
5 let timer = null;
6
7 const [time, setTime] = useState("");
8
9 const dealData = () => {
10 if (cd <= 0) {
11 setTime("");
12 return timer && clearTimeout(timer);
13 }
14 const d = parseInt(cd / (24 * 60 * 60) + "");
15 const h = parseInt(((cd / (60 * 60)) % 24) + "");
16 const m = parseInt(((cd / 60) % 60) + "");
17 const s = parseInt((cd % 60) + "");
18 setTime(`倒计时: ${d}天${h}时${m}分${s}秒`);
19 setCd(cd--); // 应该是setCd(cd - 1)
20 timer = setTimeout(() => {
21 dealData();
22 }, 1000);
23 };
24
25 useEffect(() => {
26 dealData();
27 return () => {
28 timer && clearTimeout(timer);
29 };
30 }, []);
31
32 return <div>{time}</div>;
33};
34
35export default CountDown;如上示例 1 , 2 ,因为方式 1 打破了 React 纯函数的规则,所以更加建议方式 2
第一段代码使用了普通的变量 cd 和 timer,它们被定义在组件函数的顶层。这意味着每次组件函数被调用时,都会重新创建新的 cd 和 timer,而不是保留它们的状态。这样做违反了 React 纯函数组件的规则,因为它引入了外部的状态管理。
第二段代码使用了 useRef 来创建了 cd 和 timer 这两个变量的引用。这意味着它们会被保存在组件的生命周期之外,并且在组件的多次渲染之间保持不变。因此,即使组件函数被重新调用,这些引用的值也会保持不变。这样做遵守了 React 纯函数组件的规则,因为它不引入外部状态管理。
因此,第二段代码符合 React 纯函数组件的规则,而第一段代码打破了这些规则。
【注意】