最近接触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
那么怎样才能解决这个问题?
经过在回调事件顶部加上 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>
);
}
}
复制代码
由于我使用的是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了,哈哈,以为有用的话就给个赞吧。