antd的input框onChange事件使用防抖没法获取到e.target

最近接触umi,在使用umi搭建后台项目时发现,有一个需求是在input框输入时进行防抖查询。可是Antd的input框,onChange事件触发返回的callback若是用防抖函数包裹的话,event对象的target属性是null。react

效果以下:ajax

<Input
      placeholder="任务ID"
      onChange={debounce(e => {
        console.log(e)
        if (e.target) {
          let q = e.target.value;
          setPendingId(q || undefined)
        }
      }, 500)}
      allowClear
    />
    
复制代码

打印结果:浏览器

很明显target是null,为何正常callback能够获取到,使用debouce函数就出现如此怪异的现象?bash

查阅一番以后得知,原来是React的合成事件(SyntheticEvent)致使的。异步

合成事件(SyntheticEvent)函数

事件处理程序经过 合成事件(SyntheticEvent)的实例传递,SyntheticEvent 是浏览器原生事件跨浏览器的封装。SyntheticEvent 和浏览器原生事件同样有 stopPropagation()、preventDefault() 接口,并且这些接口夸浏览器兼容。性能

事件池(Event Pooling)ui

SyntheticEvent 是池化的. 这意味着 SyntheticEvent 对象将会被重用,而且全部的属性都会在事件回调被调用后被 nullified。 这是由于性能的缘由。 所以,你不能异步的访问事件。this

经过了解事件系统,也就不难理解为何会报错了。由于通过 debounce 包装后的回调函数,变成了一个异步事件,在池化后被 nullified 了。spa

那么怎样才能解决这个问题?

  1. 对于class组件:

经过在回调事件顶部加上 e.persist() 就能够从池中移除合成事件,并容许对事件的引用保留。而且把须要异步执行的回调函数抽离出来封装,而且在组件初始化话的时候就将其 debounce 化,就能够获得咱们想要的效果。

import react, { Component } from 'react';
import { debounce } from 'lodash.debounce';

export default class Debounce extends Component {
  construtor() {
    super();
    this.callAjax = debounce(this.callAjax, 300);
  }
  
  callAjax = (value) => {
    console.log('value :: ', value);
    // call ajax
  }
  printChange(e) {
    e.persist();
    this.callAjax(e.target.value);
  }
  render() {
    return (
      <div>
        <input onChange={this.printChange} />
      </div>
    );
  }
}
复制代码
  1. 对于Function组件

由于我使用的是Hooks,因此换了个想法,使用ref,直接上代码

// 使用iseRef
import React, { useState, useEffect, useRef } from 'react';

const fileInputEl: any = useRef(null)

const callAjax = (value) => {
    setPendingId(value || undefined);
}

let printChange = debounce((e) => {
    e.persist()
    console.log(fileInputEl);

    callAjax(fileInputEl.current.input.state.value)
}, 500)

<Input
  placeholder="任务ID"
  ref={fileInputEl}
  onChange={printChange}
  allowClear
/>
复制代码

打印结果

后面发现只要不直接用debounce包裹回调函数,使用函数调用传参的方法就能够拿到e.target了。

const printChange = (e) => {
        taskChange(e.target.value)
    }
    
    const taskChange = debounce((value) => {
        setPendingId(value || undefined);
    }, 500)
    
    <Input
      placeholder="任务ID"
      ref={fileInputEl}
      onChange={printChange}
      allowClear
    />
复制代码

这里就能够拿到input中的value了,哈哈,以为有用的话就给个赞吧。

相关文章
相关标签/搜索