React中闭包陷阱的几种情及解决方案
作者:每天工作十小时
什么是闭包?
闭包是指在一个函数内部包裹函数,并且内部函数总能访问外部函数的变量。
function f1(){ var num = 10, function f2(){ alert(num) // 10 } }
特点:
1:函数套函数;
2:内部函数可以直接使用外部函数的局部变量或参数;
3:变量或参数不会被垃圾回收机制回收 GC
缺点:常驻内存 会增大内存的使用量 使用不当会造成内存泄露。
闭包陷阱以及如何解决
在react中我们使用其提供的Hooks中的useState,useEffect,useCallback 时,可能会造成闭包陷阱,下面我们来看一下出现的情况以及如何解决
useState【异步陷阱】
const [num, setNum] = useState(0) const jia = () => { setNum(num + 1) console.log(num); } return ( <div> <h1>{num}</h1> <button onClick={() => jia()}>点我+1</button> </div> )
问题:当我们点击button按钮时,会发现值在持续 +1 ,但是打印的值始终都是上一次点击的值,
因为useState修改值是异步更新,无法获取更新后的值
解决方案:
const [num, setNum] = useState(0) const numRef = useRef() const jia = () => { setNum(num + 1) setTimeout(() => { //模拟异步操作 console.log(numRef.current.innerText); }, 0) } return ( <div> <h1 ref={numRef}>{num}</h1> <button onClick={() => jia()}>点我+1</button> </div> )
使用useRef来获取元素的值
useEffect【过期问题】
const [num, setNum] = useState(0) useEffect(() => { setInterval(() => { setNum(num + 1) }, 1000) }, []) return ( <div> <h1>{num}</h1> </div> )
问题:useEffect是在页面加载时执行,如果第二个参数是一个空数组,则只执行一次,所以我们可以看到页面始终显示的都是1
解决方案:
const [num, setNum] = useState(0) useEffect(() => { let time = setInterval(() => { setNum(num + 1) clearInterval(time) }, 1000) }, [num]) return ( <div> <h1>{num}</h1> </div> )
我们可以通过在空数组中传入依赖项,使得useEffect中的逻辑在num每次更改时都会执行,并在每次执行后都清楚掉定时器
useCallback【缓存问题】
useCallback是用来进行优化的函数,他的作用是返回一个记忆化的回调函数,该回调函数仅在其依赖项发生变化时才会更新。这在处理子组件的 props 或者优化事件处理函数等场景中非常有用。
我们在父组件向子组件传递数据,并在父组件修改值,我们会发现,子组件的useCallback中打印的一直都是0
解决方案:我们在useCallback的空数组中,传入我们的依赖项 props.num 这样每次props.num 发生改变就会重新执行代码
到此这篇关于React中闭包陷阱的几种情及解决方法的文章就介绍到这了,更多相关React闭包陷阱内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!