面试被要求手写防抖函数,那就用React 函数式和类式组件实现实现

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

之前看了《金字塔原理》这本书,讲了写作时需要遵循的流程:

背景–冲突–问题–解决方案

背景:

为什么需要防抖函数,在实际开发过程中,当输入搜索框去实时获取后端请求时,输入一个字符都会去请求一次后端,

冲突:

这是非常消耗性能的,我们需要对其进行优化,当监听到input框中数据发生变化时,500ms之后才去请求一次后端接口

问题:

那么我们应该如何去解决这个问题

解决方案:

定义一个防抖函数,传入需要调取接口的方法和延迟定时器的时间,里面先定义一个定时器,返回一个内部函数,这里面判断 如果此时上一次定时器存在,则把上一次的定时器给清除,再定义一个新的定时器,在定时器中去 调用传进来的函数,并且利用apply()改变this指向,以及把args参数给传回去,我使用React 类式组件和函数式组件都尝试了一下,在防抖函数中,类式组件调用this指向组件实例,函数式组件没有this,this值为undefined

自定义防抖函数:

export function debounce(fn, waitTime = 500) {
  let time = null; //首次进来时定义一个定时器
  return function (args) {
    //普通函数内部,arguments为特殊的类数组对象。包含了函数被调用时的参数列表。
    if (time) {
      clearTimeout(time); //如果上一次定时器存在,则把上一次的定时器给清除
    }
    //设置定时器
    time = setTimeout(() => {
      console.log("this", this); //类式组件调用this指向组件实例,函数式组件没有this this值为undefined
      fn.apply(this, [args]); //fn直接调用指向window,apply改变this指向,指向调用的环境
    }, waitTime);
  };
}
复制代码

1. 函数式组件:

export default function DebounceFc() {
  const onSearch = (value: string) => console.log(value);
  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    console.log(e.target.value);
    //   在此调用后端接口
  };
  const onChangeDebounce = debounce(onChange, 500); //debounce 传入执行的方法 和延迟加载的时
  return (
    <div style={{ marginTop: 50, marginLeft: 100 }}>
      <Search
        placeholder="input search text"
        onSearch={onSearch}
        style={{ width: 200 }}
        onChange={(e) => onChangeDebounce(e)} //当输入框内数据发生变化时,调用onChangeDebounce 函数
      />
    </div>
  );
}
复制代码

打印结果:

image.png

2. 类式组件

export class Debounce1 extends Component {
  constructor(props: any) {
    super(props);
    this.onSearch = this.onSearch.bind(this);
    this.onChange = this.onChange.bind(this);
    this.onChangeDebounce = this.onChangeDebounce.bind(this);
    //onChange即是中间变量,由于onChangeDebounce是作为onChange的回调,所以不是通过实例调用的,是直接调用,所以处理函数中,会把函数当成window环境下的独立的函数调用,然后他的this指向全局window
    //this指向会丢失。解决这个问题就是给调用函数时bind(this)
    //从而使得无论事件处理函数如何传递,this指向都是当前实例化对象,如果不用bind(this),可以用箭头函数 ,箭头函数的this指向他的上下文
  }
  onSearch(value: string) {
    console.log(value);
  }
  onChange(e: React.ChangeEvent<HTMLInputElement>) {
    console.log(e.target.value);
    //   在此调用后端接口
  }
  onChangeDebounce = debounce(this.onChange, 500); //debounce 传入执行的方法 和延迟加载的时间
  render() {
    return (
      <div style={{ marginTop: 50, marginLeft: 100 }}>
        <Search
          placeholder="input search text"
          onSearch={this.onSearch}
          style={{ width: 200 }}
          onChange={this.onChangeDebounce} //当输入框内数据发生变化时,调用onChangeDebounce 函数
        />
      </div>
    );
  }
}
复制代码

打印结果:

image.png

另外:

因为之前我没有开发时没用class声明组件,直接用的hooks,然后去搜索了一下类式组件中调用函数需要用bind()去绑定一下当前组件的this,由于onChangeDebounce是作为onChange的回调,所以不是通过实例调用的,是直接调用,所以处理函数中,然后他的this指向全局window,this指向会丢失。

解决这个问题就是给调用函数时bind(this),从而使得无论事件处理函数如何传递,this指向都是当前实例化对象,如果不用bind(this),可以用箭头函数 ,箭头函数的this指向他的上下文

若文中有误,忘大佬指出

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享