New knowledge storeFront end from entry to groundFor attention, star and suggestions, update from time to time ~
Why don’t you read the total set: starting from scratch big front-end foundation journey (simple, constantly updated ~) 10,000 word long catalogue, feel good to click on the like ~
If the left side does not reach 30 likes, please kindly click, thank you ~
Debounce and throttle are common front-end utility functions.
When performing operations such as window resize, Scroll, and input box content verification, if the event processing function is called at an unlimited frequency, the burden on the browser will be increased, resulting in poor user experience. Debounce and throttle can be used to reduce the frequency of calls without compromising performance.
In general, we are used to using the loDash utility functions, which are simple and convenient, but the coder always needs to interview
Function image stabilization
When an event is continuously triggered and no event is triggered again within a certain period of time, the event handler will execute once. If the event is triggered again before the specified time, the delay will start again.
Let’s implement a simple debounce~
function debounce(fn, ms) { let timer; return function(... args) { if (timer) { clearTimeout(timer) } timer = setTimeout(() => { fn(... args) timer = null; }, ms); }}Copy the code
It is important to remember that the stabilization function should be called only once.
Function of the throttle
Ensure that an event handler is called only once in a certain period of time when an event is continuously raised.
function throttle(fn, ms) { let timer; return function(... args) { if (timer) return; canRun = false; timer = setTimeout(() => { fn(... args); timer = null; }, ms); }}Copy the code
It is important to remember that the stabilization function should be called only once.
The principle of function throttling and function stabilization is actually very simple
- Stabilization: Maintains a timer that fires after the delay, but if it fires again within the delay, the timer will be cancelled and reset. In this way, only the last operation can be triggered.
- Throttling: Maintains a timer that is set to trigger functions after delay time, but if triggered again within delay time, it will determine if any delayed calling function is not executed, if it is returned, and if not, it will trigger functions after delay time
React Hook function anti-shake and throttling
Hook up being
The simple analogy is that there’s something like this
function useDebounce(fn, time) {
return debounce(fn, time);
}
Copy the code
Perfect. Let’s write a function
export default function() {
const [counter, setCounter] = useState(0);
const handleClick = useDebounce(function() {
setCounter(counter + 1)
}, 1000)
return <div style={{ padding: 30 }}>
<Button
onClick={handleClick}
>click</Button>
<div>{counter}</div>
</div>
}
Copy the code
Click two try, ah, very good use, good, is the feeling where not quite right appearance…
Let’s do another example
export default function() { const [counter1, setCounter1] = useState(0); const [counter2, setCounter2] = useState(0); Const handleClick = useDebounce(function() {setCounter1(counter1 + 1)}, 500) UseEffect (function() {const t = setInterval(() => {setCounter2(x => x + 1)}, 500); useEffect(function() {const t = setInterval(() => {setCounter2(x => x + 1)}, 500) return () => clearInterval(t) }, []) return <div style={{ padding: 30 }}> <Button onClick={function() { handleClick() }} >click</Button> <div>{counter1}</div> <div>{counter2}</div> </div> }Copy the code
It’s just an automatic update. Click on it… Alas… there The shakers don’t work
Remember the above statement that the anti-shake function must be called only once. In a class component, either place it in constructor or when a variable function is generated, because the class component is initialized only once, and the functions bound in subsequent components are always the same, so the state saved according to the closure principle takes effect.
In functional components, internal functions are regenerated and bound to the component each time render is rendered. When a component has only one state that affects render, we
- Press the button like crazy,
- Will only trigger click events, not re-render,
- The event function of the current component binding is unchanged, and the anti-shake function is the same, so the anti-shake function works
But when there are other states that affect rendering
- Pressing the button
- Triggers the event without re-rendering
count2
Change and re-render- HandleClick is regenerated and bound to the component,
- The original function fails, the anti-shake fails, and the original function is executed after a certain delay
counter1
change
This is the comparison of the flow. Now do you understand why the normal anti-shake function cannot be used in the Reack hook?
How do you react Hook? The idea is to ensure that every time you render, the function bound to the component is the same anti-shake function.
First of all, since we want to ensure the same anti – shake function, try useCallback or useMemo. This hook can guarantee that the dependency does not change, return the same value.
Let’s add a layer of wrapping and rely on passing in an empty array to ensure that useCallback always returns the same function
function useDebounce(fn, delay) {
return useCallback(debounce(fn, delay), [])
}
export default function() {
const [counter, setCounter] = useState(0);
const handleClick = useDebounce(function() {
setCounter(counter + 1)
}, 1000)
return <div style={{ padding: 30 }}>
<Button
onClick={handleClick}
>click</Button>
<div>{counter}</div>
</div>
}
Copy the code
Use a single counter to debug this time, and guess the result?
It doesn’t change when it goes from 0 to 1. According to? If you understand closures, you should be able to understand the concept of snapshots.
Since our useCallback dependency is an empty array, the handleClick function is always a snapshot of the initialization function after the component is initialized, that is, the handleClick function is not updated during subsequent component rerendering. In the meantime, HandleClick also holds counter as a snapshot of the function when it was created, which is always 0, so even if the anti-shake function stays the same, it won’t work.
Of course, you can get the correct value of counter by setCounter(x => x + 1), but not for other scenarios.
What else guarantees data uniqueness? UseRef ~ The problem with the above method is that either there is no guarantee that the anti-shock function is unique, which causes the timer to lose effect, or there is no guarantee that the calling function is up to date, which causes the calling function to lose effect.
function useDebounce(fn, delay, dep = []) { const { current } = useRef({ fn, timer: null }); useEffect(function () { current.fn = fn; }, [fn]); return useCallback(function f(... args) { if (current.timer) { clearTimeout(current.timer); } current.timer = setTimeout(() => { current.fn(... args); }, delay); }, dep) }Copy the code
You’re done! Now you have a take-away hook anti – shake function
Hook the throttle
function useThrottle(fn, delay, dep = []) { const { current } = useRef({ fn, timer: null }); useEffect(function () { current.fn = fn; }, [fn]); return useCallback(function f(... args) { if (! current.timer) { current.timer = setTimeout(() => { delete current.timer; }, delay); current.fn(... args); } }, dep); }Copy the code
conclusion
After learning React Hook, I directly used functional components in the form of hook for most of the components. However, it is worth noting that we use hook for better and more convenient implementation of components, such as
- Instead of thinking about how to update state when the props changes,
- No need to consider use
getDerivedStateFromProps
How to trigger actions after updating data, - Or maybe you don’t have to think about how to pass
shouldComponentUpdate
Write complex judgment logic to reduce unnecessary rendering.
But please do not insist on writing functional components, especially when the internal functions of functional components will be passed to the next layer of components or the relationship between functions is very complex, how to ensure the uniqueness of functions, how to deal with dependencies will drive you crazy. At this point, it’s a good idea to reuse class components.
If you learn something new, please give me a like and let me know
This article contains: a journey of large front end foundation building from scratch (simple and profound, constantly updated ~)
Recommended reading:
-
Take you rolled a belongs to own the react project | webpack + Babel + typescript + eslint didn’t ridden a project of the couple must not to be missed, take you unlock fast development tips
-
In a few words with you to understand the “closure” | add usage scenario is very simple to explain why going?
-
Reflow and Repaint, KFC and MC are mentioned at the same time every time. The relationship is almost as close as MC beside KFC.
-
Viewport and 1 px | tools: this is a 1 px, designer: no, I can’t, this is not a design but ready to quarrel with me
-
Edible “dry” CSS layout, pure Html example, can debug | horizontal, vertical, multiple columns can watch, adjustable, can be taken away, the only, no branch
-
Front end must master “CSS cascade context” explain | handmade sample, BaoJiao package will sister with cat, what do you want?
Reference documentation
- React-hooks: How to react-hooks?
- Js anti-shake and throttling