日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
從根上理解ReactHooks的閉包陷阱(續(xù)集)

??上篇文章??我們知道了什么是 hooks 的閉包陷阱,它的產(chǎn)生原因和解決方式,并通過一個(gè)案例做了演示。

我們提供的服務(wù)有:成都網(wǎng)站建設(shè)、成都做網(wǎng)站、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、武江ssl等。為上千多家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的武江網(wǎng)站制作公司

其實(shí)那個(gè)案例的閉包陷阱的解決方式不夠完善,這篇文章我們?cè)偻晟埔幌隆?/p>

首先我們先來回顧下什么是閉包陷阱:

hooks 的閉包陷阱是指 useEffect 等 hook 中用到了某個(gè) state,但是沒有把它加到 deps 數(shù)組里,導(dǎo)致 state 變了,但是執(zhí)行的函數(shù)依然引用著之前的 state。

它的解決方式就是正確設(shè)置 deps 數(shù)組,把用到的 state 放到 deps 數(shù)組里,這樣每次 state 變了就能執(zhí)行最新的函數(shù),引用新的 state。同時(shí)要清理上次的定時(shí)器、事件監(jiān)聽器等。

我們舉了這樣一個(gè)例子:

import { useEffect, useState } from 'react';
function Dong() {
const [count,setCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count + 1);
}, 500);
}, []);
useEffect(() => {
setInterval(() => {
console.log(count);
}, 500);
}, []);
return
guang
;
}
export default Dong;

每次打印都是 0 :

解決方式就是把 count 設(shè)置到 deps 里,并添加清理函數(shù):

import { useEffect, useState } from 'react';
function Dong() {
const [count,setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount(count + 1);
}, 500);
return () => clearInterval(timer);
}, [count]);
useEffect(() => {
const timer = setInterval(() => {
console.log(count);
}, 500);
return () => clearInterval(timer);
}, [count]);

return
guang
;
}
export default Dong;

這樣就能解決閉包陷阱:

但是這種解決閉包陷阱的方式用在定時(shí)器上不是很合適。

為什么呢?

因?yàn)楝F(xiàn)在每次 count 變了就會(huì)重置定時(shí)器,那之前的計(jì)時(shí)就重新計(jì)算,這樣就會(huì)導(dǎo)致計(jì)時(shí)不準(zhǔn)。

所以,這種把依賴的 state 添加到 deps 里的方式是能解決閉包陷阱,但是定時(shí)器不能這樣做。

那還有什么方式能解決閉包陷阱呢?

useRef。

閉包陷阱產(chǎn)生的原因就是 useEffect 的函數(shù)里引用了某個(gè) state,形成了閉包,那不直接引用不就行了?

useRef 是在 memorizedState 鏈表中放一個(gè)對(duì)象,current 保存某個(gè)值。

它的源碼是這樣的:

初始化的時(shí)候創(chuàng)建了一個(gè)對(duì)象放在 memorizedState 上,后面始終返回這個(gè)對(duì)象。

這樣通過 useRef 保存回調(diào)函數(shù),然后在 useEffect 里從 ref.current 來取函數(shù)再調(diào)用,避免了直接調(diào)用,也就沒有閉包陷阱的問題了。

也就是這樣:

const fn = () => {
console.log(count);
};
const ref = useRef(fn);
useLayoutEffect(() => {
ref.current = fn;
});
useEffect(() => {
setInterval(() => ref.current(), 500);
}, []);

useEffect 里執(zhí)行定時(shí)器,deps 設(shè)置為了 [],所以只會(huì)執(zhí)行一次,回調(diào)函數(shù)用的是 ref.current,沒有直接依賴某個(gè) state,所以不會(huì)有閉包陷阱。

用 useRef 創(chuàng)建個(gè) ref 對(duì)象,初始值為打印 count 的回調(diào)函數(shù),每次 render 都修改下其中的函數(shù)為新創(chuàng)建的函數(shù),這個(gè)函數(shù)里引用的 count 就是最新的。

這里用了 useLayoutEffect 而不是 useEffect 是因?yàn)?useLayoutEffect 是在 render 前同步執(zhí)行的,useEffect 是在 render 后異步執(zhí)行的,所以用 useLayoutEffect 能保證在 useEffect 之前被調(diào)用。

這種方式避免了 useEffect 里直接對(duì) state 的引用,從而避免了閉包問題。

另外,修改 count 的地方,可以用 setCount(count => count + 1) 代替 setCount(count + 1),這樣也就避免了閉包問題:

useEffect(() => {
setInterval(() => {
setCount(count => count + 1);
}, 500);
}, []);

現(xiàn)在組件的代碼是這樣的:

import { useEffect, useLayoutEffect, useState, useRef } from 'react';
function Dong() {
const [count, setCount] = useState(0);
useEffect(() => {
setInterval(() => {
setCount(count => count + 1);
}, 500);
}, []);
const fn = () => {
console.log(count);
};
const ref = useRef(fn);
useLayoutEffect(() => {
ref.current = fn;
});
useEffect(() => {
setInterval(() => ref.current(), 500);
}, []);
return
guang
;
}
export default Dong;

測(cè)試下:

確實(shí),打印也是正常的,這就是解決閉包陷阱的第二種方式,通過 useRef 避免直接對(duì) state 的引用,從而避免閉包問題。

這段邏輯用到了多個(gè) hook,可以封裝成個(gè)自定義 hook:

function useInterval(fn, time) {
const ref = useRef(fn);
useLayoutEffect(() => {
ref.current = fn;
});
useEffect(() => {
setInterval(() => ref.current(), time);
}, []);
}

然后組件代碼就可以簡(jiǎn)化了:

function Dong() {
const [count, setCount] = useState(0);
useInterval(() => {
setCount(count + 1);
}, 500);
useInterval(() => {
console.log(count);
}, 500);
return
guang
;
}

這樣我們就用 useRef 的方式解決了閉包陷阱問題。

總結(jié)

上篇文章我們通過把依賴的 state 添加到 deps 數(shù)組中的方式,使得每次 state 變了就執(zhí)行新的函數(shù),引用新的 state,從而解決了閉包陷阱問題。

這種方式用在定時(shí)器上是不合適的,因?yàn)槎〞r(shí)器一旦被重置和重新計(jì)時(shí),那計(jì)時(shí)就不準(zhǔn)確了。

所以我們才用了避免閉包陷阱的第二種方式:使用 useRef。

useRef 能解決閉包陷阱的原因是 useEffect 等 hook 里不直接引用 state,而是引用 ref.current,這樣后面只要修改了 ref 中的值,這里取出來的就是最新的。

然后我們把這段邏輯封裝成了個(gè)自定義 hook,這樣可以方便復(fù)用。

解決 hooks 的閉包陷阱有兩種方式:

  • 設(shè)置依賴的 state 到 deps 數(shù)組中并添加清理函數(shù)。
  • 不直接引用 state,把 state 放到 useRef 創(chuàng)建的 ref 對(duì)象中再引用。

處理定時(shí)器的時(shí)候,為保證計(jì)時(shí)的準(zhǔn)確,最好使用 useRef 的方式,其余情況兩種都可以。


本文名稱:從根上理解ReactHooks的閉包陷阱(續(xù)集)
路徑分享:http://www.5511xx.com/article/djpihhg.html