在Class继承写法中,我们的防抖节流都是这样写的
import debounce from 'lodash/debounce';
export default class Search extends Component {
constructor(props) {
super(props)
this.handleSearch = debounce(this.handleSearch, 500);
}
handleSubmit = (e) => {
e.preventDefault();
this.handleSearch();
}
handleSearch = () => {
...
}
render() {
return (
<form onSubmit={this.handleSubmit}><form>
)
}
}
改写成hooks是这样
import React, {useState} from "react";
import debounce from 'lodash/debounce';
const sendQuery = (query) => console.log(`Querying for ${query}`);
const Search = () => {
const [userQuery, setUserQuery] = useState("");
const delayedQuery = debounce(q => sendQuery(q), 500);
const onChange = e => {
setUserQuery(e.target.value);
delayedQuery(e.target.value);
};
return (
<div>
<label>Search:</label>
<input onChange={onChange} value={userQuery} />
</div>
);
}
但这样子做防抖函数并没有发挥作用,仅仅是把反应时间延后了500毫秒。这是因为函数组件每次渲染结束之后,内部的变量都会被释放,重新渲染时所有的变量会被重新初始化,产生的结果就是每一次都注册和执行了setTimeout函数。想要得到正确的运行结果,必须以某种方式存储那些本会被删除的变量和方法的引用。很遗憾,没办法直接使用useState去存储,我们可以使用useRef和useCallback我们可以更简单的去解决这个问题:
const SearchFixed = () => {
const [userQuery, setUserQuery] = useState("");
const delayedQuery = useCallback(debounce(q => sendQuery(q), 500), []);
const onChange = e => {
setUserQuery(e.target.value);
delayedQuery(e.target.value);
};
return (
<div>
<label>Search Fixed:</label>
<input onChange={onChange} value={userQuery} />
</div>
);
};
或者使用useRef
const SearchFixed = () => {
const [userQuery, setUserQuery] = useState("");
const delayedQuery = useRef(debounce(q => sendQuery(q), 500)).current;
const onChange = e => {
setUserQuery(e.target.value);
delayedQuery(e.target.value);
};
return (
<div>
<label>Search Fixed:</label>
<input onChange={onChange} value={userQuery} />
</div>
);
};
也可以自定义hook去解决