成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

React18的useEffect執行兩次如何應對

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

前段時間在本地啟了一個 React Demo 項目,在編碼的過程中遇到一個很奇怪的“Bug”。

其中簡化版的代碼如下所示。

// 入口文件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!</>;};

我是萬萬沒想到,就這樣幾行簡單的代碼竟然會觸發一個“Bug”。

此“Bug”的表現為:在 Chrome 控制臺里發現 “Hello world!” 被打印了 “兩次”。

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

很是糾結一番之后依然沒想明白,于是試著去網上搜了一下,發現竟然有人同樣遇到過這個問題。

通過網上指引,同時去官網查了一下,終于得出答案。

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

二、React18 useEffect 新特性

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

如何應對

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

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

當然,人家就是這么干了,作為 React 的普通使用者,能做的就是 適應它 ,并按照它的規范來做。

1.首先先了解一下 React 中 useEffect 執行的時機

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

每次組件渲染時,React 都會更新頁面 UI,然后運行 useEffect 中的代碼。

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

Effect 在屏幕更新之后的 rendering 進程結束的時候執行。

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

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

當然,useEffect 除了在組件渲染的時候執行外,在組件卸載的時候也有相關執行操作。

在組件卸載的時候會執行 useEffect 方法的return語句。

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

如上代碼段,當組件渲染的時候會執行window.a = 100,當組件卸載的時候會執行window.a = 0。

知道了 useEffect 的執行時機,也就能明白為什么 React18 中 useEffect 會執行兩次了。

因為, React18 在開發環境中除了必要的掛載之外,還 "額外"模擬執行了一次組件的卸載和掛載。

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

2.怎么樣才能讓 Effect 執行一次?。

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

也可以理解,畢竟在 React 的未來版本中做離屏渲染的時候 useEffect 肯定會多次執行的。

而且,即使是當前版本,在做頁面的前進后退也會面臨觸發多次 useEffect。

所以,解決辦法其實就是解決 重復掛載卸載之后 應用正常工作了。

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

我們知道 useEffect 支持返回一個函數,在組件卸載的時候就會執行該函數。

因此,通常正確解法就是 實現清理函數,并將其在 useEffect 中返回。

當然,不同的 Effect 需要有不同的清理方式。

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

1)清理事件監聽

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

對于事件監聽類函數,在返回函數內部“取消掉事件監聽”即可。

2-1)重置頁面數據,清理屬性狀態

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

對于一些頁面屬性的變更,在返回函數內部將其變更的屬性進行還原。

2-2)重置頁面數據,還原元素狀態

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 />;}

涉及到元素狀態的,比如播放器之類,需要對(元素)播放器的狀態進行重置。

2-3)重置頁面數據,彈窗類。

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

如果是默認彈窗類,這種也算是元素狀態,同樣需要對其(彈出)狀態進行重置。

3-1)異步請求頁面數據處理,處理異步數據渲染

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

如上代碼,對于異步請求數據并渲染這一類。

我們可以設置一個 標識位,做到對 請求返回的數據 僅做一次處理與渲染setTodos(json)。

codesandbox 測試代碼段

3-2)異步請求頁面數據處理,處理接口請求

上面的方法雖然僅會渲染一次,但是請求依然發起了多次。

如果不希望請求多次,也可以使用請求接口數據的緩存方案,對返回數據進行緩存。

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]);

對于異步請求,除了可以處理渲染頻率,還可以對接口的請求本身做緩存。

在前面3-1的基礎上,緩存接口返回的數據,下次請求的時候如果已經有緩存數據了就直接用,無須再次發起請求。

4)無須清理類

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

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

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

5)日志 log 上報類

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

對于日志上報類,其實也可以算是無須清理類,但是又有點特殊。

因為,對于日志類,首先在開發環境中我們其實是無須進行上報的,畢竟這種日志打上去也沒啥用。

當然,如果是要對上報日志本身這個進行調試等必須上報的情形,這種也有三種應對方式:

方式一,在本地開發環境使用 console.log 來代替 reportLog。方式二,取消掉嚴格模式(StrictMode) 方式三,構建一個 production版本啟動,或者將其部署到 QA 環境,部署的時候,指定 production 模式。

借鑒鏈接:大神地址:epoos

總結

到此這篇關于React18的useEffect執行兩次該如何應對的文章就介紹到這了,更多相關React18 useEffect執行兩次內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: JavaScript
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
国产日产欧美精品一区二区三区| 亚洲毛片在线| 欧美三级午夜理伦三级中文幕| 亚洲免费在线| 亚洲一区二区免费视频| 99精品热6080yy久久| 国产精品视频在线看| 成+人+亚洲+综合天堂| 欧美综合亚洲图片综合区| 亚洲第一二三四区| 999亚洲国产精| 综合av第一页| 黄色日韩精品| 国产精品久久久久国产精品日日| 欧美91福利在线观看| 精品欧美一区二区在线观看| 国产69精品久久久久777| 欧美一区二区人人喊爽| 国产曰批免费观看久久久| 欧美人狂配大交3d怪物一区| 久久99日本精品| 欧美三级韩国三级日本一级| 久久精品国产99国产精品| 欧美日韩国产成人在线免费| 国产在线精品一区二区三区不卡 | 欧美激情一区| 国产欧美一区二区三区在线老狼| 欧美国产91| 国产精品拍天天在线| 国产精品啊啊啊| 亚洲欧美一区二区三区国产精品| 中文精品视频| 五月婷婷综合激情| 在线观看中文字幕不卡| 精品一区二区免费| 日韩欧美成人激情| 欧美一区二区三区免费看| 国产精品高潮久久久久无| 亚洲人成网站在线观看播放| 一区二区三区成人在线视频 | 欧美一区二区在线视频| av电影在线不卡| 欧美国产激情二区三区| 136国产福利精品导航网址| 一区二区三区在线免费视频| 久久久久久久高潮| 激情六月婷婷综合| 欧美精品一区二区三区久久久| 欧美91精品| 一区二区三区四区视频精品免费 | 美女日韩在线中文字幕| 美女视频网站久久| 欧美精品第一页| 成人精品鲁一区一区二区| 日本一区二区免费在线| 国产欧美日本| 另类小说视频一区二区| 欧美大尺度电影在线| 好吊一区二区三区| 亚洲福利电影网| 在线播放视频一区| 欧美日韩精品一本二本三本| 亚洲激情五月婷婷| 欧美专区在线观看一区| 不卡视频在线看| 亚洲免费高清视频在线| 老司机精品导航| 成人在线视频一区二区| 国产精品高潮呻吟| 91久久久免费一区二区| 成人av在线播放网址| 亚洲激情自拍偷拍| 欧美日韩国产高清一区二区| 欧美精品三级| 日本在线不卡视频一二三区| 日韩免费高清视频| 一区二区三区精品国产| 国产在线精品视频| 国产精品丝袜久久久久久app| 老牛嫩草一区二区三区日本| 成人av在线网| 亚洲精品国产一区二区精华液 | 久久亚洲一区二区三区明星换脸| 亚洲看片免费| 韩国午夜理伦三级不卡影院| 中文字幕第一区二区| 91黄视频在线| 欧美成人69av| 日韩制服丝袜av| 2017欧美狠狠色| 久久精品道一区二区三区| www.性欧美| 天天综合色天天| 国产三区在线成人av| 久久在线精品| 欧美日本一区| 久久精品国产亚洲高清剧情介绍 | 老妇喷水一区二区三区| av不卡免费在线观看| 丝袜亚洲另类丝袜在线| 26uuu国产电影一区二区| 国产精品亚洲不卡a| 国产91富婆露脸刺激对白| 亚洲激情av在线| 精品国产一区二区三区久久久蜜月| 国产精品美女黄网| 99久久伊人网影院| 免费成人在线观看| 亚洲欧美在线高清| 日韩免费看的电影| 老牛嫩草一区二区三区日本| 欧美日韩三区| 国产中文字幕一区| 亚洲精品国久久99热| 欧美变态tickling挠脚心| 久久亚洲国产精品一区二区| 欧美日韩国产三区| 国产揄拍国内精品对白| 一区二区三区不卡在线观看| 2014亚洲片线观看视频免费| 欧美综合欧美视频| 一区二区三区四区国产| 99re成人精品视频| 国产在线麻豆精品观看| 亚洲123区在线观看| 中文一区在线播放| 日韩一区二区三区四区| 在线视频中文字幕一区二区| 99爱精品视频| 91麻豆自制传媒国产之光| 韩国女主播成人在线观看| 一区二区三区国产豹纹内裤在线| 久久久亚洲欧洲日产国码αv| 欧美另类变人与禽xxxxx| 亚洲欧美大片| 一区在线电影| 91网站在线播放| 国产乱人伦精品一区二区在线观看 | 国模套图日韩精品一区二区| 亚洲一区二区偷拍精品| 国产精品乱码一区二三区小蝌蚪| 欧美成人猛片aaaaaaa| 欧美精品一二三四| 色又黄又爽网站www久久| 国产欧美日韩伦理| 激情婷婷亚洲| 亚洲欧美一级二级三级| 成人亚洲一区二区一| 国内外精品视频| 美女精品自拍一二三四| 图片区小说区区亚洲影院| 亚洲影视在线播放| 亚洲激情自拍偷拍| 亚洲人精品一区| 国产精品久久久久桃色tv| 国产日韩欧美一区二区三区乱码| 日韩精品一区二区三区四区视频| 欧美精品1区2区3区| 在线免费观看视频一区| 久久久久久国产精品一区| 国产农村妇女精品一二区 | 亚洲欧美中日韩| 国产精品免费视频网站| 国产拍揄自揄精品视频麻豆| 久久色中文字幕| 欧美本精品男人aⅴ天堂| 91精品国产高清一区二区三区蜜臀| 91成人在线精品| 在线中文字幕一区二区| 色婷婷香蕉在线一区二区| 久久精品日产第一区二区三区| 国产精品试看| 国产欧美在线| 国产欧美日韩一级| 亚洲一区二区三区涩| 亚洲在线网站| 久久久久久黄| 久久久水蜜桃| 日本二三区不卡| 欧美三级蜜桃2在线观看| 欧美日韩国产综合草草| 欧美精品国产精品| 91精品麻豆日日躁夜夜躁| 91精品国产乱码久久蜜臀| 日韩美一区二区三区| 精品1区2区在线观看| 精品电影一区二区三区| 2023国产精品自拍| 国产午夜亚洲精品不卡| 国产欧美综合在线| 中文字幕一区二区在线播放 | 91精品国产欧美日韩| 欧美一级一级性生活免费录像| 日韩精品一区二| 国产亚洲精品bt天堂精选| 国产精品久久久久久久久久免费看| 亚洲天堂成人网| 亚洲小说欧美激情另类| 丝袜a∨在线一区二区三区不卡| 人人狠狠综合久久亚洲|