目录
useThrottle: 封装了一个节流的hook
useCallback的作用(性能优化)
不用Hook封装节流方法的情况,看是怎么形成闭包的:
import { useEffect, useCallback, useRef } from 'react';function useThrottle(fn: Function, delay: any, dep = []) {//用useRef --确保 useCallback里面的值是最新的,如果用useState会形成闭包,导致return不了最新的函数const { current } = useRef({ fn, timer:null })useEffect(function () {current.fn = fn;}, [fn]);return useCallback(function f(this: any) {if (!current.timer) {current.timer = setTimeout(() => {delete current.timer}, delay)current.fn.call(this, arguments)}}, dep)
}export default useThrottle;
使用:
/** 点击事件 */function handleClickJitter(type = '') {if(type == 'debounce') {setText("已处理")}else {console.log("执行一次");setThrottleText(`${new Date().getSeconds()}`)}}return (
useCalback就是对函数起一个“缓存”作用,当该函数被父组件作为props传递给字组件子组件时,让props“无变化”,因此达到不会让子组件重复渲染的目的。
函数式子组件需要搭配 React.memo使用!!!
无论子组件是pureComponent还是用React.memo进行包裹,都会让子组件render,而配合useCallback使用就能让子组件不随父组件render。
const BtnMemo = React.memo((props: any) => {const { click } = propsconsole.log("渲染一次");return ()
})const throttleJitterCon = (props: IThrottleJitterConProps) => {const [throttleText, setThrottleText] = useState("初始")/** 点击事件 */function handleClickJitter(type = '') {if(type == 'debounce') {setText("已处理")}else {console.log("执行一次");setThrottleText(`${new Date().getSeconds()}`)}}return (
看反例,去掉useCallback的情况:
function useThrottle(fn: Function, delay: any, dep = []) {//用useRef --确保 useCallback里面的值是最新的,如果用useState会形成闭包,导致return不了最新的函数const { current } = useRef({ fn, timer:null })useEffect(function () {current.fn = fn;}, [fn]);return function f(this: any) {if (!current.timer) {current.timer = setTimeout(() => {delete current.timer}, delay)current.fn.call(this, arguments)}}
}
可以看到,执行一次后,btnMemo就会跟着渲染一次。(造成了不必要的渲染,复杂业务逻辑下下,会对项目有影响)
const BtnMemo = React.memo((props: any) => {const { click } = propsreturn ()
})const throttleJitterCon = (props: IThrottleJitterConProps) => {const [throttleText, setThrottleText] = useState("初始")/** 节流:在一定时间内只能执行一次 */const throttleFunc = (fn: Function, delay:any) => {let timer: anyreturn useCallback(function(this:any) {console.log("throttleText--useCallback",throttleText); if (!timer) {timer = setTimeout(() => {timer = null}, delay)fn.apply(this, arguments)}},[])}console.log("throttleText++++++++++++",throttleText);/** 点击事件 */function handleClickJitter(type = '') {if(type == 'debounce') {setText("已处理")}else {setThrottleText(`${new Date().getSeconds()}`)}}return ({handleClickJitter('throttle')},3000)} />{throttleText} );
}export default throttleJitterCon;
throttleFunc函数里是可以访问外部作用域的 throttleText变量。也验证了闭包的含义:
我的源代码: https://github.com/BBbila/my-mixed-bag/tree/main/src/ReatHooks/throttleJitter