成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_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国内精品久久久久久久
毛片不卡一区二区| 亚洲www啪成人一区二区麻豆| 欧美无人高清视频在线观看| 国产精品日韩精品欧美精品| 亚洲人成人一区二区三区| 欧美人成网站| 国模吧视频一区| 尤物精品在线| 国产精品最新自拍| 色综合久久99| 在线看不卡av| 欧美人伦禁忌dvd放荡欲情| 国产一区激情在线| 自拍偷拍国产亚洲| 亚洲精品免费看| 亚洲高清免费视频| 日韩高清不卡在线| 久久99久久精品| 国产精品中文欧美| 欧美国产三区| av成人天堂| 91久久人澡人人添人人爽欧美 | 国产精品一区视频| 久久久综合网| 欧美一级高清片| 久久这里只有精品视频网| 国产精品视频观看| 亚洲h动漫在线| 国产成人综合自拍| 国产在线观看一区| 色综合激情五月| 欧美电影免费观看高清完整版在 | 亚洲欧美日韩久久精品| 视频一区视频二区在线观看| 国产一区日韩二区欧美三区| 92国产精品观看| 999亚洲国产精| 欧美少妇xxx| 国产欧美一区二区在线| 丝袜国产日韩另类美女| 成人综合婷婷国产精品久久免费| 国产综合自拍| 午夜不卡在线视频| 国产又粗又猛又爽又黄91精品| 成人理论电影网| 99在线观看免费视频精品观看| 一本到不卡精品视频在线观看| 精品久久久久一区| 一区二区三区av电影| 国产精品自产自拍| 一本一本久久| 精品国产区一区| 亚洲国产精品尤物yw在线观看| 国产二区国产一区在线观看| 亚洲久久成人| 日韩久久久精品| 亚洲与欧洲av电影| 99免费精品视频| 91久久精品一区二区三区| 国产清纯白嫩初高生在线观看91| 蜜乳av一区二区| 激情欧美丁香| 精品免费日韩av| 丝袜诱惑制服诱惑色一区在线观看| 99国产精品久久久久久久久久| 久久综合福利| 国产精品入口麻豆原神| 国产在线精品一区二区夜色| 国产欧美日韩综合一区在线观看| 精品嫩草影院久久| 韩国欧美国产1区| 亚洲一区二区三区精品在线观看 | 国产精品视频看| 成人av网站免费| 欧美性一二三区| 亚洲丶国产丶欧美一区二区三区| 91免费观看国产| 欧美一二区视频| 国内精品免费在线观看| 久久一区二区三区av| 亚洲欧美电影院| 欧美亚韩一区| 国产午夜精品一区二区三区视频 | 国产91精品一区二区麻豆网站| 亚洲欧美日韩视频二区| 国产精品你懂的在线| jizz一区二区| 精品日本一线二线三线不卡| 韩国成人福利片在线播放| 欧美曰成人黄网| 天使萌一区二区三区免费观看| 91久久奴性调教| 色综合久久久久久久久久久| 亚洲毛片av在线| 精品91久久久久| 中文乱码免费一区二区| 亚洲欧美亚洲| 国产丝袜美腿一区二区三区| 99久久国产综合精品色伊| 日韩一区二区三免费高清| 国产精品原创巨作av| 制服丝袜亚洲精品中文字幕| 国内精品写真在线观看| 在线播放/欧美激情| 国产成人在线看| 日韩免费性生活视频播放| 国产.欧美.日韩| 精品理论电影在线| 91污在线观看| 成人免费一区二区三区在线观看| 国产精品v一区二区三区| 中文字幕亚洲不卡| 国产精品美女诱惑| 天天色图综合网| 北条麻妃国产九九精品视频| 日韩一区二区免费在线观看| 99麻豆久久久国产精品免费优播| 久久综合五月天婷婷伊人| 欧美成人免费在线| 亚洲欧美日韩人成在线播放| 亚洲欧美久久久| 久久精品国产一区二区| 欧美一区2区视频在线观看| a4yy欧美一区二区三区| 亚洲欧洲日产国码二区| 亚洲一区久久| 国产麻豆成人精品| 国产精品网站在线观看| 亚洲国产免费| 日本色综合中文字幕| 欧美一级高清片在线观看| 午夜久久美女| 午夜精品久久久| 欧美电影免费提供在线观看| 国内一区二区三区| 婷婷丁香激情综合| 精品va天堂亚洲国产| 日韩视频一区| 国产在线播精品第三| 亚洲国产精品成人综合| 久久成人在线| 成人精品gif动图一区| 日韩伦理av电影| 欧美三级日韩三级国产三级| 91视频一区二区三区| 同产精品九九九| 久久网站热最新地址| 另类图片国产| 99久久夜色精品国产网站| 夜夜揉揉日日人人青青一国产精品| 欧美老肥妇做.爰bbww| 亚洲动漫精品| 欧美成人国产一区二区| 女同一区二区| 日韩1区2区日韩1区2区| 久久久欧美精品sm网站| 亚洲欧美成人| 91啪亚洲精品| 欧美aaa在线| 最好看的中文字幕久久| 欧美区在线观看| 国产欧美日韩在线播放| 91尤物视频在线观看| 韩国v欧美v日本v亚洲v| 亚洲一区二区三区在线看| 欧美精品一区二区三区蜜桃| 老司机午夜免费精品视频| 国产精品二区二区三区| 成人综合婷婷国产精品久久蜜臀 | 日本 国产 欧美色综合| 国产精品久久久久三级| 日韩欧美一卡二卡| 老司机免费视频久久| 99精品国产高清一区二区| 不卡一区在线观看| 日韩二区三区四区| 亚洲色图丝袜美腿| 久久免费午夜影院| 日韩一区国产二区欧美三区| 一本久久综合亚洲鲁鲁五月天 | 不卡电影免费在线播放一区| 日韩电影在线看| 亚洲一二三区视频在线观看| 国产精品嫩草影院com| 精品国产一区二区三区忘忧草 | 亚洲综合一区二区三区| 国产精品国产自产拍在线| 久久久99免费| 精品久久久久久最新网址| 欧美精品久久久久久久久老牛影院| 久久人人97超碰人人澡爱香蕉 | 欧美一区二区在线不卡| 欧美视频日韩视频| 欧美视频第二页| 欧美三级一区二区| 欧美午夜精品电影| 欧美群妇大交群中文字幕| 欧美一区二区三区播放老司机| 欧美日韩在线免费视频| 欧美日韩一区二区三区高清|