React中防抖节流示例

React中防抖节流研究


以下是代码。此处为了通用的节流防抖在React中形成闭包,是将节流防抖第一次调用函数在componentWillMount时赋值给了state中的变量

import React from 'react'
class PropsParent extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            msgText: '请输入消息内容',
            throttleFn: '', // 节流函数引用
            throttleFn1: '', // 防抖函数引用
            throttleFn2: '', // 防抖函数引用
            throttleFn3: '' // 防抖函数引用
        }
    }
    render() {
        return (
            <div>
                <input placeholder='输入改变传递给子组件的内容' onChange= { (e) => {this.changeText(e)}}></input>
                <div>{this.state.msgText}</div>
            </div>
        )
    }
    UNSAFE_componentWillMount() {
        // 节流防抖设置
        // 为了使throttle形成闭包,只调用一次throttle,之后由其引用throttleFn来调用
        this.setState({
            debounceFn: this.debounce(this.handleChangeText, 1000),
            throttleFn1: this.throttle1(this.handleChangeText, 1000),
            throttleFn2: this.throttle2(this.handleChangeText, 1000),
            throttleFn3: this.throttle3(this.handleChangeText, 1000)
        })
    }
    // 防抖函数 一定时间段内没有再触发事件,事件处理函数才会执行一次
    debounce(fn, delay) {
        let that = this
        return function() {
            let args = arguments;  
            clearTimeout(fn.id)
            fn.id = setTimeout(() => {
                fn.call(that, args)
            }, delay)
        }
    }
    // 节流函数(时间戳) 每delay时间才执行一次 
    // 优点 第一次立即执行
    // 缺点 最后一次执行时间到最后一次触发事件时间间隔小于delay,那么将不会执行最后一次事件
    throttle1(fn,delay) {
        let that = this
        // 形成闭包后,此数据不变  
        var prev = Date.now();    
      return function() { 
            var now = Date.now();
            let args = arguments;
            if(now - prev >= delay) {
                fn.call(that, args)
                prev = Date.now();
            }
      }
    }
     // 节流函数(定时器) 每delay时间才执行一次 
    // 缺点 第一次不会立即执行 最后一次触发事件若是在timer未被清空的这段事件内,就不会被执行
    throttle2(fn,delay) {
        let that = this
        // 形成闭包后,此数据不变  
        var timer = null
      return function() { 
            let args = arguments;
            if(!timer) {
                timer = setTimeout(() => {
                    fn.call(that, args)
                    timer = null
                }, delay)
            }
      }
    }
     // 节流函数(定时器)
     // 时间戳+定时器,当第一次触发事件时马上执行事件处理函数,最后一次触发事件后也还会执行一次事件处理函数。
    // 在节流函数内部使用开始时间startTime、当前时间curTime与delay来计算剩余时间remaining,
    // 当remaining<=0时表示该执行事件处理函数了(保证了第一次触发事件就能立即执行事件处理函数和每隔delay时间执行一次事件处理函数)。
    // 如果还没到时间的话就设定在remaining时间后再触发 (保证了最后一次触发事件后还能再执行一次事件处理函数)。
    // 当然在remaining这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。
    throttle3(fn,delay) {
        let that = this
        // 形成闭包后,此数据不变  
        var startTime = Date.now();
        var timer = null
      return function() { 
            let args = arguments;
            var curTime = Date.now();
            // 在remaining这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态
            var remaining = delay - (curTime -startTime)
            clearTimeout(timer)
            if(remaining <= 0) {
                // 保证了第一次触发事件就能立即执行事件处理函数和每隔delay时间执行一次事件处理函数)
                fn.call(that, args)
                startTime = Date.now();
            } else {
                // 保证了最后一次触发事件后还能再执行一次事件处理函数
                timer = setTimeout(() => {
                    fn.call(that, args)
                    timer = null
                },remaining)
            }
      }
    }
    handleChangeText(args) {
        console.log(args)
        this.setState({
            msgText: args[0]
        })
    }
    changeText(e) {
         this.state.debounceFn(e.target.value)
        // this.state.throttleFn1(e.target.value)
        // this.state.throttleFn2(e.target.value)
        // this.state.throttleFn3(e.target.value)
    }
}

export default PropsParent

补充内容:
在函数式组件中使用节流防抖,需要使用useRef或useMemo缓存返回的节流防抖函数,否则每次更新页面会重新执行生成的节流防抖函数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值