日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

React18的useEffect執(zhí)行兩次如何應(yīng)對(duì)

瀏覽:27日期:2022-06-12 14:12:25
目錄一、執(zhí)行兩次的useEffect。二、React18 useEffect 新特性如何應(yīng)對(duì)1.首先先了解一下 React 中 useEffect 執(zhí)行的時(shí)機(jī)2.怎么樣才能讓 Effect 執(zhí)行一次?。###3.具體的解決方法總結(jié)一、執(zhí)行兩次的useEffect。

前段時(shí)間在本地啟了一個(gè) React Demo 項(xiàng)目,在編碼的過程中遇到一個(gè)很奇怪的“Bug”。

其中簡(jiǎn)化版的代碼如下所示。

// 入口文件import { StrictMode } from 'react';import * as ReactDOMClient from 'react-dom/client';import App from './App';const root = ReactDOMClient.createRoot(document.getElementById('root'));root.render( <StrictMode> <App /> </StrictMode>);// 組件代碼import React, { useEffect } from 'react';const App = () => { useEffect(() => { console.log('組件掛載完成!'); }, []); return <>Hello world!</>;};

我是萬(wàn)萬(wàn)沒想到,就這樣幾行簡(jiǎn)單的代碼竟然會(huì)觸發(fā)一個(gè)“Bug”。

此“Bug”的表現(xiàn)為:在 Chrome 控制臺(tái)里發(fā)現(xiàn) “Hello world!” 被打印了 “兩次”。

刷新之后依然如此,當(dāng)時(shí)就給我整懵了,第一感覺就是,這怎么可能?

很是糾結(jié)一番之后依然沒想明白,于是試著去網(wǎng)上搜了一下,發(fā)現(xiàn)竟然有人同樣遇到過這個(gè)問題。

通過網(wǎng)上指引,同時(shí)去官網(wǎng)查了一下,終于得出答案。

這不是 Bug,這是 React18 新加的特性。

二、React18 useEffect 新特性

1.這是 React18 才新增的特性。2.僅在開發(fā)模式("development")下,且使用了嚴(yán)格模式("Strict Mode")下會(huì)觸發(fā)。 生產(chǎn)環(huán)境("production")模式下和原來(lái)一樣,僅執(zhí)行一次。3.之所以執(zhí)行兩次,是為了模擬立即卸載組件和重新掛載組件。 為了幫助開發(fā)者提前發(fā)現(xiàn)重復(fù)掛載造成的 Bug 的代碼。 同時(shí),也是為了以后 React的新功能做鋪墊。 未來(lái)會(huì)給 React 增加一個(gè)特性,允許 React 在保留狀態(tài)的同時(shí),能夠做到僅僅對(duì)UI部分的添加和刪除。 讓開發(fā)者能夠提前習(xí)慣和適應(yīng),做到組件的卸載和重新掛載之后, 重復(fù)執(zhí)行 useEffect的時(shí)候不會(huì)影響應(yīng)用正常運(yùn)行。

如何應(yīng)對(duì)

看過文檔以及了解他們這么做的本意之后,我也能夠理解他們會(huì)這樣做了。

只是,對(duì)于這種半強(qiáng)迫式操作多少有些不喜歡,感覺是在代碼中”被強(qiáng)迫打一針疫苗?”。

當(dāng)然,人家就是這么干了,作為 React 的普通使用者,能做的就是 適應(yīng)它 ,并按照它的規(guī)范來(lái)做。

1.首先先了解一下 React 中 useEffect 執(zhí)行的時(shí)機(jī)

Every time your component renders, React will update the screen and then run thecode inside useEffect.

每次組件渲染時(shí),React 都會(huì)更新頁(yè)面 UI,然后運(yùn)行 useEffect 中的代碼。

Effects run at the end of the rendering process after the screen updates

Effect 在屏幕更新之后的 rendering 進(jìn)程結(jié)束的時(shí)候執(zhí)行。

從上面可以得出結(jié)論,React 中的 useEffect 執(zhí)行時(shí)機(jī)是在組件渲染之后(類似于 window(component).onload ?)。

因此,對(duì)于某些“副作用”的渲染,比如異步接口請(qǐng)求,事件綁定等操作我們通常都放在 useEffect 中執(zhí)行。

當(dāng)然,useEffect 除了在組件渲染的時(shí)候執(zhí)行外,在組件卸載的時(shí)候也有相關(guān)執(zhí)行操作。

在組件卸載的時(shí)候會(huì)執(zhí)行 useEffect 方法的return語(yǔ)句。

useEffect(() => { window.a = 100; return (window.a = 0);}, []);

如上代碼段,當(dāng)組件渲染的時(shí)候會(huì)執(zhí)行window.a = 100,當(dāng)組件卸載的時(shí)候會(huì)執(zhí)行window.a = 0。

知道了 useEffect 的執(zhí)行時(shí)機(jī),也就能明白為什么 React18 中 useEffect 會(huì)執(zhí)行兩次了。

因?yàn)椋?React18 在開發(fā)環(huán)境中除了必要的掛載之外,還 "額外"模擬執(zhí)行了一次組件的卸載和掛載。

既然知道了原因,那么,接下來(lái)就是想辦法解決了。

2.怎么樣才能讓 Effect 執(zhí)行一次?。

對(duì)于這個(gè)問題,官方文檔上面有一句原話:The right question isn’t “how to run an Effect once,” but “how to fix my Effect so that it works after remounting”.翻譯一下,就是說:正確的問題不是“怎么樣讓 Effect 執(zhí)行一次”,而是“怎樣修復(fù)我的 Effect,讓它在(重復(fù))掛載之后正常工作”

也可以理解,畢竟在 React 的未來(lái)版本中做離屏渲染的時(shí)候 useEffect 肯定會(huì)多次執(zhí)行的。

而且,即使是當(dāng)前版本,在做頁(yè)面的前進(jìn)后退也會(huì)面臨觸發(fā)多次 useEffect。

所以,解決辦法其實(shí)就是解決 重復(fù)掛載卸載之后 應(yīng)用正常工作了。

###3.具體的解決方法

我們知道 useEffect 支持返回一個(gè)函數(shù),在組件卸載的時(shí)候就會(huì)執(zhí)行該函數(shù)。

因此,通常正確解法就是 實(shí)現(xiàn)清理函數(shù),并將其在 useEffect 中返回。

當(dāng)然,不同的 Effect 需要有不同的清理方式。

在常用 Effect 分類下,大致有如下幾類清理。

1)清理事件監(jiān)聽

useEffect(() => { function handleScroll(e) { console.log(e.clientX, e.clientY); } window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll);}, []);

對(duì)于事件監(jiān)聽類函數(shù),在返回函數(shù)內(nèi)部“取消掉事件監(jiān)聽”即可。

2-1)重置頁(yè)面數(shù)據(jù),清理屬性狀態(tài)

useEffect(() => { const node = ref.current; node.style.opacity = 1; // Trigger the animation return () => { node.style.opacity = 0; // Reset to the initial value };}, []);

對(duì)于一些頁(yè)面屬性的變更,在返回函數(shù)內(nèi)部將其變更的屬性進(jìn)行還原。

2-2)重置頁(yè)面數(shù)據(jù),還原元素狀態(tài)

import { useEffect, useRef } from 'react';function VideoPlayer({ src, isPlaying }) { const ref = useRef(null); useEffect(() => { if (isPlaying) { ref.current.play(); } else { ref.current.pause(); } }); return <video ref={ref} src={src} loop playsInline />;}

涉及到元素狀態(tài)的,比如播放器之類,需要對(duì)(元素)播放器的狀態(tài)進(jìn)行重置。

2-3)重置頁(yè)面數(shù)據(jù),彈窗類。

useEffect(() => { const dialog = dialogRef.current; dialog.showModal(); return () => dialog.close();}, []);

如果是默認(rèn)彈窗類,這種也算是元素狀態(tài),同樣需要對(duì)其(彈出)狀態(tài)進(jìn)行重置。

3-1)異步請(qǐng)求頁(yè)面數(shù)據(jù)處理,處理異步數(shù)據(jù)渲染

useEffect(() => { let ignore = false; async function startFetching() { const json = await fetchTodos(userId); // 這里執(zhí)行是異步的,所以第一次執(zhí)行到此處的時(shí)候組件已經(jīng)被卸載了 // 此時(shí)的 ignore 已經(jīng)被 return 里面的方法置為 true 了 // 所以這里第一次執(zhí)行的時(shí)候不執(zhí)行 setTodos(json) // setTodos 其實(shí)是在第二次執(zhí)行的時(shí)候才觸發(fā) if (!ignore) { setTodos(json); } } startFetching(); return () => { ignore = true; };}, [userId]);

如上代碼,對(duì)于異步請(qǐng)求數(shù)據(jù)并渲染這一類。

我們可以設(shè)置一個(gè) 標(biāo)識(shí)位,做到對(duì) 請(qǐng)求返回的數(shù)據(jù) 僅做一次處理與渲染setTodos(json)。

codesandbox 測(cè)試代碼段

3-2)異步請(qǐng)求頁(yè)面數(shù)據(jù)處理,處理接口請(qǐng)求

上面的方法雖然僅會(huì)渲染一次,但是請(qǐng)求依然發(fā)起了多次。

如果不希望請(qǐng)求多次,也可以使用請(qǐng)求接口數(shù)據(jù)的緩存方案,對(duì)返回?cái)?shù)據(jù)進(jìn)行緩存。

const cache = useRef(null);useEffect(() => { let ignore = false; async function startFetching() { if (!cache.current) { cache.current = await fetchTodos(userId); } if (!ignore) { setTodos(cache.current); } } startFetching(); return () => { ignore = true; };}, [userId]);

對(duì)于異步請(qǐng)求,除了可以處理渲染頻率,還可以對(duì)接口的請(qǐng)求本身做緩存。

在前面3-1的基礎(chǔ)上,緩存接口返回的數(shù)據(jù),下次請(qǐng)求的時(shí)候如果已經(jīng)有緩存數(shù)據(jù)了就直接用,無(wú)須再次發(fā)起請(qǐng)求。

4)無(wú)須清理類

并不是所有的 useEffect 函數(shù)都需要清理,對(duì)于一些沒有副作用的函數(shù),我們完全可以不做處理

useEffect(() => { const map = mapRef.current; map.setZoomLevel(zoomLevel);}, [zoomLevel]);

如上代碼所示,setZoomLevel 方法僅僅是設(shè)置一下 Dom 元素的層級(jí)。這種操作無(wú)論同時(shí)執(zhí)行多少次都不會(huì)有太大的影響,所以對(duì)于這一類我們就隨他去吧,畢竟線上也不會(huì)執(zhí)行多次。

5)日志 log 上報(bào)類

useEffect(() => { reportLog({ name: 'viewCount' });}, []);

對(duì)于日志上報(bào)類,其實(shí)也可以算是無(wú)須清理類,但是又有點(diǎn)特殊。

因?yàn)椋瑢?duì)于日志類,首先在開發(fā)環(huán)境中我們其實(shí)是無(wú)須進(jìn)行上報(bào)的,畢竟這種日志打上去也沒啥用。

當(dāng)然,如果是要對(duì)上報(bào)日志本身這個(gè)進(jìn)行調(diào)試等必須上報(bào)的情形,這種也有三種應(yīng)對(duì)方式:

方式一,在本地開發(fā)環(huán)境使用 console.log 來(lái)代替 reportLog。方式二,取消掉嚴(yán)格模式(StrictMode) 方式三,構(gòu)建一個(gè) production版本啟動(dòng),或者將其部署到 QA 環(huán)境,部署的時(shí)候,指定 production 模式。

借鑒鏈接:大神地址:epoos

總結(jié)

到此這篇關(guān)于React18的useEffect執(zhí)行兩次該如何應(yīng)對(duì)的文章就介紹到這了,更多相關(guān)React18 useEffect執(zhí)行兩次內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: JavaScript
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
精品视频91| 日本午夜免费一区二区| 国产成人精品一区二区免费看京 | 亚洲另类黄色| 乱一区二区av| 青青在线精品| 性欧美长视频| 国产精品高潮呻吟久久久久| 亚洲精品成人一区| 黄色日韩在线| 久久国产欧美日韩精品| 亚洲精品免费观看| 久久中文字幕av| 免费观看在线色综合| 亚洲人成高清| 国产色综合网| 美国三级日本三级久久99| 91精品一区二区三区综合在线爱| 久久国产日韩| 国产精品色在线网站| 五月激情久久| 在线看片福利| 天堂av在线一区| 亚洲午夜av| 精品三级国产| 久久久精品五月天| 亚洲第一区色| 国产精品久久久久久久免费软件 | 四虎4545www国产精品| 精品成人18| 亚洲免费网址| 免费日韩一区二区三区| 国产精品免费看| 免费观看在线色综合| 亚洲播播91| 1024精品久久久久久久久| 蜜桃一区二区三区在线观看| 日韩免费看片| 美女尤物国产一区| 日韩在线一区二区| 国产成人1区| 久久激情五月激情| 婷婷综合成人| 中文精品在线| 国产乱码午夜在线视频| 尤物精品在线| 激情亚洲影院在线观看| 高清在线一区| 久久wwww| 日韩激情精品| 亚洲视频二区| www.九色在线| 丝袜av一区| 日本欧美在线看| 7m精品国产导航在线| 久久久久91| 日本一区二区中文字幕| 日韩av黄色在线| 欧美国产日本| 国产成人免费精品| 久久久成人网| 日韩精品影视| 欧美精品资源| 99在线|亚洲一区二区| 亚洲一二av| 亚洲字幕久久| 日本aⅴ亚洲精品中文乱码 | 蜜臀精品久久久久久蜜臀| 免费人成黄页网站在线一区二区| 国产99精品| 国产精一区二区| 亚洲国产一区二区三区在线播放| 欧美日韩视频| 久久99蜜桃| 日韩超碰人人爽人人做人人添| 国产精品分类| а√天堂中文在线资源8| 亚洲网站视频| 亚洲精品午夜av福利久久蜜桃| 97国产精品| 国产成人久久精品麻豆二区 | 亚洲香蕉网站| 香蕉成人久久| 日产欧产美韩系列久久99| 国产一区二区三区四区五区 | 欧洲av一区二区| 麻豆成人综合网| 亚洲黑丝一区二区| 日韩高清一区在线| 亚洲一级少妇| 国产激情久久| 国产综合亚洲精品一区二| 日韩精品一区二区三区中文| 伊人久久在线| 国产精品男女| 免费在线小视频| 日韩和欧美的一区| 亚洲天堂久久| 麻豆一区二区三| 视频一区在线播放| 欧洲精品一区二区三区| 久久亚洲图片| 美女av在线免费看| 欧美日韩一区二区国产| 欧美日韩激情| 婷婷国产精品| 亚洲一区免费| 99久久激情| 日本午夜大片a在线观看| 日韩亚洲精品在线观看| 99在线精品视频在线观看| 国产成人精品亚洲线观看| 亚洲三级网址| 成人在线网站| 精品亚洲精品| 精品国产18久久久久久二百| 夜久久久久久| 国产精品.xx视频.xxtv| 日韩高清一区在线| 日韩精品中文字幕吗一区二区 | 日韩影院在线观看| 日产精品一区| 五月激情久久| 成人福利视频| 天堂√8在线中文| 国产尤物精品| 久久精品123| 国产精品欧美在线观看| 亚洲免费播放| 国产欧美一区二区三区米奇 | 精品免费av在线| 色爱av综合网| 精品久久精品| 成人影视亚洲图片在线| 99成人超碰| 日韩中文字幕不卡| 国产香蕉精品| 人人精品亚洲| 日本综合精品一区| 精品三级国产| 美女久久精品| 国产精品nxnn| 精品一区视频| 久久久精品午夜少妇| 国产韩日影视精品| 天堂日韩电影| 日本不卡视频在线| 久久精品国产99国产精品| 久久精品国产在热久久| 亚洲无线一线二线三线区别av| 欧美精品三级在线| 国产 日韩 欧美一区| 中文字幕在线免费观看视频| 国产精品日韩久久久| 国际精品欧美精品| 免费成人性网站| 91国内精品| 久久九九精品| 日本少妇一区二区| 99久久久久国产精品| 欧美日韩国产一区二区三区不卡| 亚洲一区国产| 麻豆91小视频| 久久亚洲图片| 日韩高清成人| 国产一区二区三区久久| 国产亚洲精品v| 久久久91麻豆精品国产一区| 国产精品嫩草99av在线| 日韩专区精品| 国产福利亚洲| 亚州av日韩av| 婷婷亚洲五月| 国产亚洲一区在线| 亚洲永久字幕| 水野朝阳av一区二区三区| 首页国产欧美日韩丝袜| 亚洲麻豆一区| 精品少妇av| 欧美精品国产白浆久久久久| 视频一区视频二区在线观看| 欧美日韩国产v| 欧美日韩视频网站| 国产成人精选| 亚洲激情另类| 午夜久久av| 中文字幕一区二区精品区| 国产精品主播| 亚洲毛片在线免费| 黄色亚洲在线| 91精品国产成人观看| 欧美日韩亚洲一区在线观看| 日韩精品一二三四| 国产伊人久久| 久久亚洲一区| 麻豆一区二区99久久久久| 麻豆免费精品视频| 免费在线视频一区| 日韩激情一区| 欧美少妇精品|