Learn how to use Debounce and Throttle in React in one article

In daily front-end development, two functions, debounce and throttling, are often used. The debounce function can effectively control only the last request to be executed within a period of time. For example, when inputting in the search box, only the last request will be executed. The request interface is made only after the input is completed. The throttling function executes a request every once in a while.

When developing React applications, it is different from ordinary js, and through the react hook mechanism, these two functions can be more conveniently realized.

防抖函数(Debounce)

As can be seen from the above figure, after using the anti-shake function, no matter how many times we click in the middle, it will only be executed once at the end of the delay.

使用 js 简单实现防抖函数

function debounce(fn: any, wait: number) {let timer: anyreturn (...args: any) => {// @ts-ignoreconst context = thisif (timer) clearTimeout(timer)timer = setTimeout(() => {timer = nullfn.apply(context,args)}, wait)}
} 

The principle of anti-shake is relatively simple, which is to use a closure to save the timer and the passed function, and then clear the previous timer each time it is entered, so that the delay wait will start calculating again every time, so as to achieve only An effect that executes once after the delay has expired.

在 React Input 中使用防抖函数

Suppose there is a demand for users to search for products by entering product names. Then it is impossible to request the background interface every time the user inputs. The best way to deal with it is to add an anti-shake function and only request it once after the user completes the input. In this way This can avoid multiple invalid calls to the background interface.

The traditional way to implement this function is as follows:

// 防抖函数,间隔时间为 2 秒
const changeDebounce = useCallback(debounce(handleChange, 2000), [])

// 搜索框,非受控组件
<Input onChange={(e) => changeDebounce(e)} style={
   
   {width: 150, marginRight: 20}}/> 

It can be seen that the above method is more suitable for uncontrolled components. If it is a controlled component, the React Hooks mechanism can be used to implement it:

// 传递给 Input 组件的值
const [value, setValue] = useState('')

// useEffect 钩子函数
useEffect(() => {const getData = setTimeout(() => {if (!value) returninfo('异步请求....')}, 2000)return () => clearTimeout(getData)
}, [value])

// 搜索框,受控组件
<Input value={value} onChange={(e) => setValue(e.target.value)} style={
   
   {width: 150, marginRight: 20}}/> 

It can be seen that the useEffect hook function can easily implement the anti-shake function. The reason is that it depends on the change of value. After each value change, the useEffect hook will execute the clearing logic, that is, the function returned by return will be executed again, so This ensures that after entering content multiple times, the logic will only be executed once after the interval.

If it's a little more abstract, we can extract this logic into a custom hook:

const useDebounce = <V>(value: V, wait: number) => {const [debounceValue,setDebounceValue] = useState(value)useEffect(() => {const timer = setTimeout(() => setDebounceValue(value),wait)return () => clearTimeout(timer)},[value,wait])return debounceValue
} 

In the custom hook, another state is used to save and update the state. It will only be updated when the interval time is up, and then the new state is returned. It can be used like this on the page, directly relying on the returned state, like this Every time this status changes, when the interval is up, an asynchronous request can be made.

const debounceValue = useDebounce(value,2000)

useEffect(() => {if (!debounceValue) returninfo('异步请求....')
},[debounceValue]) 

The final effect is as follows:

节流函数(Throttle)

The above picture is easier to see the application scenarios of the throttling function. It is generally used in situations where the number of executions is very intensive, such as scrolling the screen, which means a bit of current limiting.

使用 js 实现节流函数

function throttle(fn: any, wait: number) {let inThrottle = falsereturn (...args: any) => {// @ts-ignoreconst context = thisif (!inThrottle) {inThrottle = truefn.apply(context, args)setTimeout(() => {inThrottle = false}, wait)}}
} 

The way to implement the throttling function is to use variables to control whether to execute the logic. The boolean value inThrottle is used here for control. If the time has not expired, it will always be in a true state until the time is up and the logic starts to be executed.

The following is a small example to demonstrate the drag effect when the throttling function is not used:

<div style={
   
   {width: 50, height: 50, backgroundColor: 'blue'}} draggable={true} onDrag={() => { info('被拖动了~~~') }}
/> 

It can be seen that without trying the throttling function, it is executed many, many times as soon as it is dragged. If this is a request, it will definitely max out the interface, so in this case, throttling must be used. function to control the frequency. The following is the effect of using the throttling function:

const changeThrottle = useCallback(throttle(() => {info('异步请求....')
}, 2000), [])

<div style={
   
   {width: 50, height: 50, backgroundColor: 'blue'}} draggable={true}onDrag={changeThrottle}
/> 

After adding the throttling function, no matter how fast you drag, the execution logic will be executed according to the frequency of the interval.

在 React 中使用节流函数

We can also use React Hook to implement the throttling function like the anti-shake function above:

const useThrottle = <V>(value: V, wait: number) =>{const [throttledValue, setThrottledValue] = useState<V>(value)const lastExecuted = useRef<number>(Date.now())useEffect(() => {if (Date.now() >= lastExecuted.current + wait) {lastExecuted.current = Date.now()setThrottledValue(value)} else {const timerId = setTimeout(() => {lastExecuted.current = Date.now()setThrottledValue(value)}, wait)return () => clearTimeout(timerId)}}, [value, wait])return throttledValue
} 

Here, time comparison is mainly used to control whether to update throttledValue to achieve the throttling effect. It can be used like this in the component:

const [value, setValue] = useState(0)
const throttledValue = useThrottle(value, 2000)

useEffect(() => {if (value === 0) returninfo('throttle 异步请求....')
}, [throttledValue])

const handleDrag = () => {setValue(prevState => prevState + 1)
}

<div style={
   
   {width: 50, height: 50, backgroundColor: 'blue'}} draggable={true} onDrag={handleDrag}
/> 

The final effect is the same as using the throttle function directly.

总结

In front-end development, anti-shake and throttling functions are almost essential skills. Their implementation principles are inseparable from the characteristics of js closure. In React, the same effect can be achieved by using custom hooks. Some It may be more convenient in certain scenarios, but overall the essence is still the same.

## Finally, we have compiled 75 JS high-frequency interview questions, and provided answers and analysis. This can basically guarantee that you can cope with the interviewer's questions about JS. ![](https://img-blog.csdnimg.cn/856589141da54a1fafc99ea9e7b017fe.png#pic_center) ![](https://img-blog.csdnimg.cn/72699310cddb41aa99c5f4387dfbefdf.png#pic_center) ![](https : //img-blog.csdnimg.cn/431073429e9340ceb3c3880c0066c179.png#pic_center) ![](https://img-blog.csdnimg.cn/3eeb2c5bec44424da347971f2cb7ffbf.png#pic_center) > **Friends in need can click below Get the card and share it for free**

Guess you like

Origin blog.csdn.net/weixin_53312997/article/details/129248753