最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React18的useEffect執(zhí)行兩次如何應對

 更新時間:2023年07月14日 16:19:21   作者:翼晗  
這篇文章主要給大家介紹了關于React18的useEffect執(zhí)行兩次如何應對的相關資料,文中通過實例代碼介紹的非常詳細,對大家學習或者使用React具有一定的參考借鑒價值,需要的朋友可以參考下

一、執(zhí)行兩次的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!</>;
};

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

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

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

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

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

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

二、React18 useEffect 新特性

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

如何應對

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

對于這個問題,官方文檔上面有一句原話: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í)行一次”,而是“怎樣修復我的 Effect,讓它在(重復)掛載之后正常工作”

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2-2)重置頁面數據,還原元素狀態(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)的,比如播放器之類,需要對(元素)播放器的狀態(tài)進行重置。

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

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

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

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

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

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

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

codesandbox 測試代碼段

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

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

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

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的基礎上,緩存接口返回的數據,下次請求的時候如果已經有緩存數據了就直接用,無須再次發(fā)起請求。

4)無須清理類

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

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

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

5)日志 log 上報類

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

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

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

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

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

借鑒鏈接:大神地址:epoos

總結

到此這篇關于React18的useEffect執(zhí)行兩次該如何應對的文章就介紹到這了,更多相關React18 useEffect執(zhí)行兩次內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • React-redux實現小案例(todolist)的過程

    React-redux實現小案例(todolist)的過程

    這篇文章主要為大家詳細介紹了React-redux實現小案例(todolist)的過程,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • react?實現表格列表拖拽排序的示例

    react?實現表格列表拖拽排序的示例

    本文主要介紹了react?實現表格列表拖拽排序,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-02-02
  • React組件渲染后對DOM的操作方式

    React組件渲染后對DOM的操作方式

    這篇文章主要介紹了React組件渲染后對DOM的操作方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • React使用useSearchParams同步URL和查詢參數的方法

    React使用useSearchParams同步URL和查詢參數的方法

    在開發(fā)React應用時,我們經常遇到一種場景:用戶在搜索框輸入關鍵詞,篩選出一個列表,然后希望把這個結果分享給同事,在React Router v6中,useSearchParams這個Hook就是專門用來處理這個問題的,本文將介紹如何使用它來實現 URL 與應用狀態(tài)的同步,需要的朋友可以參考下
    2025-12-12
  • Yarn安裝項目依賴報error?An?unexpected?error?occurred:?“XXXXX:ESOCKETTIMEOUT”問題解決

    Yarn安裝項目依賴報error?An?unexpected?error?occurred:?“XXXXX:E

    這篇文章主要為大家介紹了Yarn安裝項目依賴報error?An?unexpected?error?occurred:?“XXXXX:ESOCKETTIMEOUT”問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • React中props驗證不足的問題及解決方案

    React中props驗證不足的問題及解決方案

    在?React?開發(fā)中,props?是組件間通信的重要方式,通過?props,父組件可以向子組件傳遞數據和回調函數,然而,如果對?props?的驗證不足,可能會導致類型錯誤、運行時錯誤或難以調試的問題,本文將探討?React?中?props?驗證不足的常見問題,并提供解決方案
    2025-03-03
  • react配置webpack-bundle-analyzer項目優(yōu)化踩坑記錄

    react配置webpack-bundle-analyzer項目優(yōu)化踩坑記錄

    這篇文章主要介紹了react配置webpack-bundle-analyzer項目優(yōu)化踩坑記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • React Native仿美團下拉菜單的實例代碼

    React Native仿美團下拉菜單的實例代碼

    本篇文章主要介紹了React Native仿美團下拉菜單的實例代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • 使用React?SSR寫Demo一學就會

    使用React?SSR寫Demo一學就會

    這篇文章主要為大家介紹了使用React?SSR寫Demo實現教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • react-native-fs實現文件下載、文本存儲的示例代碼

    react-native-fs實現文件下載、文本存儲的示例代碼

    本篇文章主要介紹了react-native-fs實現文件下載、文本存儲的示例代碼,具有一定的參考價值,有興趣的可以了解下
    2017-09-09

最新評論

乌什县| 博爱县| 城口县| 邛崃市| 仁化县| 高陵县| 池州市| 临泉县| 静乐县| 文昌市| 西乌珠穆沁旗| 华池县| 陆良县| 安溪县| 文安县| 泰和县| 梁河县| 修水县| 汝阳县| 库车县| 如东县| 香港| 景宁| 慈溪市| 临海市| 乡城县| 廉江市| 屯昌县| 沁阳市| 东乡| 福建省| 汉川市| 兴义市| 兴宁市| 都匀市| 东乡族自治县| 睢宁县| 阿拉善右旗| 白河县| 新巴尔虎左旗| 独山县|