美文网首页
function component 关于定时器的一个坑 202

function component 关于定时器的一个坑 202

作者: 讨厌西红柿 | 来源:发表于2020-01-10 18:10 被阅读0次

最近在慢慢由class component转用function component代替,写法清爽了很多,不过带来的问题也有点多。。。

问题

首先让我们使用function component实现一个倒计时功能

import React, {useEffect, useState} from 'react';
import { Button } from 'antd-mobile';

let ClearTimer = null;

const Test = ()=>{

    const [seconds, setSeconds] = useState(10);

    useEffect(()=>{
        ClearTimer = setInterval(countDown, 1000);

        return clearUp;
    }, []);

    const clearUp = ()=>{
        clearInterval(ClearTimer);
    };

    const countDown = ()=>{
        let num = seconds - 1;
        if(num < 1){
            clearInterval(ClearTimer);
        }
        setSeconds(num);
    };

    return (
        <div>
            <Button>剩余时间{seconds}s</Button>
        </div>
    )
};

export default Test;

代码很简单,利用setInterval逐秒递减。实际跑起来后,会发现 根本没有递减!!!一直卡在9s不动。

原因

究其原因,还是seconds取值的问题。countDown是个闭包传入setInterval,其中seconds的值,在传入的时候就已经决定了,不会再取当前值,所以每次执行countDown函数seconds的值都是10。

解决办法

1. setState传入函数参数

更改countDown的写法,setSeconds不直接传入数值,而是传入一个callback

const countDown = ()=>{
        setSeconds((pre)=>{
            console.log('pre = ', pre);
            let num = pre - 1;
            if(num <= 0){
                clearInterval(ClearTimer);
            }

            return num;
        });
    };

callback的参数,为当前的seconds值,而不再是闭包里的值,此时计算结果已经是正确了。

2. 利用useEffectsetTimer实现(不推荐,容易影响其他逻辑)

首先修改useEffect,让其依赖seconds进行刷新,setInterval替换成setTimeout

useEffect(()=>{
        ClearTimer = setTimeout(countDown, 1000);

        return clearUp;
    }, [seconds]);

再简单改下countDown,只要调用setSeconds就行

const countDown = ()=>{
        seconds > 0 && setSeconds(seconds - 1);
    };

更改后,每次setSeconds都会引起useEffect函数的刷新动作,从而重新生成一个新Timer,保证了闭包内seconds的值始终是最新的

总结

由闭包引起的变量值没更新的问题,在class component中比较少见,而在function component中一不注意就会踏入陷阱。在需要根据当前state值计算下一个state时,尽量传入setState的函数参数,使用其参数state来进行计算,避免受其他环境的影响,比如闭包、别处的引用修改。
注意:使用useReducer虽能解决数值更新的问题,却也无法解决闭包值的问题。

相关文章

网友评论

      本文标题:function component 关于定时器的一个坑 202

      本文链接:https://www.haomeiwen.com/subject/vbcmactx.html