React16,17,18,19更新對比

文章目錄

  • 前言
  • 一、16更新
  • 二、17更新
  • 三、18更新
  • 四、19更新
  • 總結


在這里插入圖片描述

前言

總結react 16,17,18,19所更新的內容,并且部分會涉及到原理講解。


一、16更新

1、在16.8之前更新,還是基于class組件的升級和維護更新。并且更新了一個重要的架構,Fiber架構。
什么是Fiber:Fiber架構的核心是“Fiber”節點,它是工作的基本單位。每個React元素都對應一個Fiber節點,這些節點構成了一個工作單元的樹狀結構。Fiber節點包含組件的類型、其對應的DOM節點信息以及子節點和兄弟節點的引用等信息。
2、而16.8的更新,是react的一個重要更新呢版本。
更新內容:

  1. 引入Hooks,新增許多hooks的api

  2. Hooks解決了什么問題:
    ① 組件復用:
    之前:
    函數組件無法直接管理狀態和生命周期,所以組件復用通常依賴類組件,和高階組件實現。
    例如:

    // 高階組件
    function withLoading(WrappedComponent) {return class extends React.Component {state = { isLoading: false };componentDidMount() {this.setState({ isLoading: true });setTimeout(() => {this.setState({ isLoading: false });}, 2000);}render() {const { isLoading } = this.state;return (<div>{isLoading ? <div>Loading...</div> : <WrappedComponent {...this.props} />}</div>);}};
    }
    // 被包裹的組件
    class MyComponent extends React.Component {render() {return <div>My Component Content</div>;}
    }
    // 使用高階組件
    const MyComponentWithLoading = withLoading(MyComponent);
    // 渲染
    ReactDOM.render(<MyComponentWithLoading />, document.getElementById("root"));
    

    hooks出現之后:
    例如:

    // 自定義 Hook
    function useLoading() {const [isLoading, setIsLoading] = useState(false);React.useEffect(() => {setIsLoading(true);const timer = setTimeout(() => {setIsLoading(false);}, 2000);return () => clearTimeout(timer); // 清理副作用}, []);return isLoading;
    }
    // 函數組件
    function MyComponent() {const isLoading = useLoading();return (<div>{isLoading ? <div>Loading...</div> : <div>My Component Content</div>}</div>);
    }
    // 渲染
    ReactDOM.render(<MyComponent />, document.getElementById("root"));
    

    ② 生命周期函數復雜性:
    在類組件中,常見的生命周期方法包括:
    constructor:初始化狀態。
    componentDidMount:組件掛載后執行。
    componentDidUpdate:組件更新后執行。
    componentWillUnmount:組件卸載前執行。
    使用 Hooks 模擬生命周期

    1. 初始化狀態(constructor)
      在函數組件中,狀態可以通過 useState 初始化。

    2. 模擬 componentDidMount
      使用 useEffect 的回調函數,當組件掛載后執行。

    3. 模擬 componentDidUpdate
      使用 useEffect 的依賴數組,當依賴項變化時執行。

    4. 模擬 componentWillUnmount
      使用 useEffect 的返回值(清理函數),在組件卸載前執行。
      直接示例:

      class MyComponent extends React.Component {constructor(props) {super(props);this.state = {data: null,count: 0};}componentDidMount() {console.log("Component did mount");this.fetchData();}componentDidUpdate(prevProps, prevState) {console.log("Component did update");if (prevState.count !== this.state.count) {console.log(`Count changed from ${prevState.count} to ${this.state.count}`);}}componentWillUnmount() {console.log("Component will unmount");this.clearData();}fetchData = () => {// 模擬數據加載setTimeout(() => {this.setState({ data: "Loaded data" });}, 1000);};clearData = () => {console.log("Clearing data");this.setState({ data: null });};render() {const { data, count } = this.state;return (<div><h1>{data || "Loading..."}</h1><button onClick={() => this.setState({ count: count + 1 })}>Increment</button></div>);}
      }
      

      hooks模擬:

      function MyComponent() {const [data, setData] = React.useState(null);const [count, setCount] = React.useState(0);// 模擬 componentDidMountReact.useEffect(() => {console.log("Component did mount");fetchData();}, []); // 空依賴數組表示只在掛載時執行// 模擬 componentDidUpdateReact.useEffect(() => {console.log("Component did update");console.log(`Count changed to ${count}`);}, [count]); // 依賴數組包含 count,表示當 count 變化時執行// 模擬 componentWillUnmountReact.useEffect(() => {return () => {console.log("Component will unmount");clearData();};}, []); // 空依賴數組表示只在卸載時執行const fetchData = () => {// 模擬數據加載setTimeout(() => {setData("Loaded data");}, 1000);};const clearData = () => {console.log("Clearing data");setData(null);};return (<div><h1>{data || "Loading..."}</h1><button onClick={() => setCount(count + 1)}>Increment</button></div>);
      }
      

二、17更新

1、新的JSX轉化,不需要手動引入react

  1. React 16
    babel-loader會預編譯JSX為 React.createElement(…)

  2. React 17
    React 17中的 JSX 轉換不會將 JSX 轉換為 React.createElement,而是自動從 React 的 package 中引入react并調用。而是React 的運行時調用jsx 和 jsxs 函數:react/jsx-runtime 模塊提供了 jsx 和 jsxs 函數,分別用于處理單個子元素和多個子元素的情況。這些函數在運行時被調用,用于創建 React 元素。
    jsx與 React.createElement 相比,jsx 函數在處理子元素和 key 值時更加高效。例如,key 值在 jsx 函數中作為第三個參數直接傳遞,而不是像在 React.createElement 中那樣作為屬性對象的一部分。
    優勢:
    減少包體積
    簡化代碼:開發者不再需要在每個組件文件頂部顯式引入 React,使得組件代碼更加簡潔。
    優化包大小:由于不再需要導入整個 React 對象,構建工具可以更好地優化輸出代碼,從而減小輸出包的大小。
    高效參數處理
    參數結構優化:jsx 函數的參數結構更加合理。它將 children 放在了 props 對象中,并將 key 作為單獨的參數傳遞。這種參數結構使得 React 在處理元素時可以更高效地訪問和處理 children 和 key,減少了不必要的屬性查詢和處理邏輯。
    子元素處理優化:在 React 17 之前,React.createElement 的子元素是作為后續參數傳遞的,這在處理多個子元素時可能會導致性能問題。而 jsx 函數將子元素作為數組傳遞給 children 屬性,這種方式更加清晰且易于優化。
    性能優化空間
    靜態分析優化:由于 jsx 函數的實現更加標準化和簡潔,編譯器可以更容易地對 JSX 代碼進行靜態分析和優化。例如,編譯器可以在編譯時進行常量提升、代碼壓縮等優化操作,從而生成更高效的代碼。
    減少動態屬性查詢:jsx 函數消除了對動態屬性查找的需要,這在一定程度上減少了運行時的性能開銷。雖然現代 JavaScript 引擎對動態屬性查詢進行了優化,但在大規模應用中,這種優化仍然可以帶來一定的性能提升

    例如:

    import { jsx as _jsx } from 'react/jsx-runtime';
    function App() {return _jsx('h1', { children: 'Hello' }, '1');
    }
    

2、事件代理更改
17中,不在document對象上綁定事件,改為綁定于每個react應用的rootNode節點,因為各個應用的rootNode肯定不同,所以這樣可以使多個版本的react應用同時安全的存在于頁面中,不會因為事件綁定系統起沖突。react應用之間也可以安全的進行嵌套。
3、事件池(event pooling)的改變

4、異步執行
17將副作用清理函數(useEffect)改為異步執行,即在瀏覽器渲染完畢后執行。
5、forwardRef 和 memo組件的行為
React 17中forwardRef 和 memo組件的行為會與常規函數組件和class組件保持一致。它們在返回undefined時會報錯。

三、18更新

注意:v18的新特性是使用現代瀏覽器的特性構建的,徹底放棄對 IE 的支持。

  1. 并發模式
    18引入了并發特性,并發特性允許React在渲染過程中中斷和恢復工作,從而更好地響應用戶交互和系統事件,與傳統的同步渲染不同,并發渲染將渲染任務拆分為多個小任務,并根據優先級動態調度這些任務。
    實現原理
    Fiber架構:React 18使用Fiber架構來管理渲染任務。Fiber節點包含組件的類型、狀態、props等信息,并允許React在渲染過程中暫停和恢復。Fiber架構使用雙端隊列(work-in-progress tree和current tree)來管理渲染任務。
    時間切片:React將長時間的渲染任務拆分成多個較短的時間片,以避免阻塞主線程。雖然React內部自動管理時間切片,但開發者可以通過控制更新任務的優先級來間接影響時間切片的分配。
    優先級調度:React引入了任務優先級的概念,將任務分為不同的優先級,如高優先級任務(用戶交互、動畫等)和低優先級任務(數據加載、復雜計算等)。React會根據任務的優先級動態調度渲染任務,確保高優先級任務能夠及時得到處理。
    中斷與恢復:在渲染過程中,如果瀏覽器資源緊張或有其他高優先級的任務需要執行,React可以暫停當前的渲染任務,釋放資源給更重要的任務。一旦資源變得可用,React會恢復之前的渲染任務,并繼續執行剩余的小任務。
    如何使用并發特性
    啟用并發模式:通過將應用切換到并發模式,開發者可以充分利用并發渲染的優勢。示例代碼如下:

    import ReactDOM from 'react-dom/client';
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<App />);
    
  2. 更新render API

    // v17
    import ReactDOM from 'react-dom'
    import App from './App'
    ReactDOM.render(<App />, document.getElementById('root'))
    // v18
    import ReactDOM from 'react-dom/client'
    import App from './App'
    ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<App />)
    
  3. 自動批處理
    批處理是指 React 將多個狀態更新,聚合到一次 render 中執行,以提升性能
    在v17的批處理只會在事件處理函數中實現,而在Promise鏈、異步代碼、原生事件處理函數中失效。而v18則所有的更新都會自動進行批處理。

    // v17
    const handleBatching = () => {// re-render 一次,這就是批處理的作用setCount((c) => c + 1)setFlag((f) => !f)
    }
    // re-render兩次
    setTimeout(() => {setCount((c) => c + 1)setFlag((f) => !f)
    }, 0)// v18
    const handleBatching = () => {// re-render 一次setCount((c) => c + 1)setFlag((f) => !f)
    }
    // 自動批處理:re-render 一次
    setTimeout(() => {setCount((c) => c + 1)setFlag((f) => !f)
    }, 0)

    如果不想批處理,可以用flushSync強制同步處理,同步執行更新

  4. 新api
    1、startTransition
    示例:如果一個渲染任務較重的tab頁面切換,包裹后可以不阻塞其交互點擊行為。
    原理:降低渲染優先級,優先處理用戶交互行為,渲染行為延后

    import { startTransition } from 'react';
    function TabContainer() {const [tab, setTab] = useState('about');function selectTab(nextTab) {startTransition(() => {setTab(nextTab);});}
    }
    

    2、useTransition
    提供了一個帶有isPending標志的 Hook useTransition來跟蹤 transition 狀態,用于過渡期。
    startTransition回調可以嵌套和處理異步方法

    function TabContainer() {const [isPending, startTransition] = useTransition();const [tab, setTab] = useState('about');function selectTab(nextTab) {startTransition(() => {setTab(nextTab);});}
    }
    

    3、useDeferredValue
    類似于上一個hooks標記一個state為延遲更新數據,標記為非緊急更新狀態。

    import { useState, useDeferredValue } from 'react';
    function SearchPage() {const [query, setQuery] = useState('');const deferredQuery = useDeferredValue(query);
    }
    

    4、useId
    useId支持同一個組件在客戶端和服務端生成相同的唯一的 ID,原理就是每個 id 代表該組件在組件樹中的層級結構

四、19更新

1、支持元數據標簽
文檔元數據支持:支持在組件中渲染 <title><link><meta> 標簽,并自動提升到文檔的 <head> 部分
2、 新增Hooks

  1. useOptimistic
    用于管理樂觀更新。當執行某個操作時,可以先假設操作成功,并立即更新 UI,然后在操作完成后根據實際結果調整狀態。比如點贊、評論、加入購物車等功能,我們都可以先假設成功,再根據接口返回來調整。

  2. useActionState
    用于管理與用戶操作相關的狀態。它能夠記錄和回放用戶操作,幫助實現更復雜的交互和調試功能。

    function ChangeName({ currentName }) {const [error, submitAction, isPending] = useActionState(async (prev, formData) => {const error = await updateName(formData.get("name"));if (error) return error;return null;});return (<form action={submitAction}><input type="text" name="name" defaultValue={currentName} /><button type="submit" disabled={isPending}>Update</button>{error && <p>{error}</p>}</form>);}
    
  3. use
    它可以讓你讀取類似于 Promise 或 context 的資源的值。可以在if中使用

    import { use } from 'react';
    function MessageComponent({ messagePromise }) {const message = use(messagePromise);const theme = use(ThemeContext);
    
  4. 優化
    React 編譯器可以自動緩存計算結果來優化組件,減少不必要的重新讀取。在許多情況下,開發人員無需明確使用記憶化鉤子,如 useMemo 和 useCallback。例如,以往需要手動使用 useMemo 來緩存昂貴的計算結果,現在可以直接寫代碼,編譯器會自動優化。

  5. 棄用forwardRef

    const MyInput = forwardRef(function MyInput(props, ref) {return (<label>{props.label}<input ref={ref} /></label>);
    });
    

    可以直接使用ref

    function MyInput(props) {return (<label>{props.label}<input ref={props.ref} /></label>);
    }
    
  6. 寫法優化
    <Context> 作為提供者,可以直接使用 <Context> 作為提供者,而不是 <Context.Provider>


總結

React 16:引入 Fiber 架構,提升渲染性能,新增錯誤邊界等功能。
React 17:事件系統重構,新的 JSX 轉換機制,優化事件處理。
React 18:并發渲染、自動批處理、服務器組件,性能大幅提升。
React 19:引入 Actions 和表單狀態管理 API,自動優化性能,簡化開發體驗

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/87154.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/87154.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/87154.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【git】有兩個遠程倉庫時的推送、覆蓋、合并問題

當你執行 git pull origin develop(或默認的 git pull)時,Git 會把遠端 origin/develop 的提交合并到你本地的 develop,如果遠端已經丟掉(或從未包含)你之前在私庫(priv)里提交過的改動,那這些改動就會被「覆蓋」,看起來就像「本地修改沒了」。 要解決這個問題,分…

Spring Boot 集成國內AI,包含文心一言、通義千問和訊飛星火平臺實戰教程

Spring Boot 集成國內AI&#xff0c;包含文心一言、通義千問和訊飛星火平臺實戰教程 一、項目結構二、添加Maven依賴三、配置API密鑰 (application.yml)四、配置類1. AI配置類 (AiProperties.java)2. 啟用配置類 (AiConfig.java) 五、服務層實現1. 文心一言服務 (WenxinService…

Elastic Search 學習筆記

1. Elasticsearch 是什么&#xff1f;有哪些應用場景&#xff1f; Elasticsearch 整體原理流程&#xff1f; Elasticsearch 是一個為海量數據提供近實時搜索和分析能力的分布式搜索引擎&#xff0c;廣泛應用于全文檢索、日志分析和大數據處理場景中。 Elasticsearch 整體原理…

動態規劃之斐波那契數(一)

解法一&#xff1a;遞歸 class Solution { public:int fib(int n) {if(n<2) return n;return fib(n-1)fib(n-2);} }; 解法二&#xff1a;dp class Solution { public:int fib(int N) {if (N < 1) return N;int dp[2];dp[0] 0;dp[1] 1;for (int i 2; i < N; i) {…

如何設置爬蟲的訪問頻率?

設置爬蟲的訪問頻率是爬蟲開發中的一個重要環節&#xff0c;尤其是在爬取大型網站&#xff08;如1688&#xff09;時&#xff0c;合理的訪問頻率可以避免對目標網站造成過大負擔&#xff0c;同時也能降低被封禁的風險。以下是一些常見的方法和建議&#xff0c;幫助你合理設置爬…

前端面試六之axios

一、axios簡介 Axios 是一個基于 Promise 的 HTTP 客戶端&#xff0c;用于瀏覽器和 Node.js 環境。在瀏覽器端&#xff0c;Axios 的底層實現是基于原生的 XMLHttpRequest&#xff08;XHR&#xff09;。它對 XHR 進行了封裝&#xff0c;增加了 Promise 支持、自動轉換 JSON 數據…

模板方法模式Template Method Pattern

模式定義 定義一個操作中算法的骨架&#xff0c;而將一些步驟延遲到子類中&#xff0c;模板方法使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟 類行為型模式 模式結構 AbstractClass&#xff1a;抽象類ConcreteClass&#xff1a;具體子類 只有類之間的繼…

【行云流水AI筆記】游戲里面的強化學習使用場景

強化學習在游戲中的應用已從早期的棋類博弈擴展到現代復雜游戲的全流程優化&#xff0c;以下是結合最新技術進展的核心應用場景及典型案例&#xff1a; 一、競技游戲的策略突破 1. 策略博弈類游戲 代表案例&#xff1a;AlphaGo/AlphaZero&#xff08;圍棋&#xff09;、Alph…

使用Python和PyTorch框架,基于RetinaNet模型進行目標檢測,包含數據準備、模型訓練、評估指標計算和可視化

下面是一個完整的實現方案,使用Python和PyTorch框架,基于RetinaNet模型進行目標檢測,包含數據準備、模型訓練、評估指標計算和可視化。 import os import numpy as np import matplotlib.pyplot as plt import torch import torchvision from torchvision.models.detection…

springboot服務如何獲取pod當前ip方案及示例

在 Kubernetes 集群中&#xff0c;Spring Boot 服務獲取 Pod 當前 IP 的方案主要有兩種&#xff1a;通過環境變量注入 或 通過 Java 代碼動態獲取網絡接口 IP。以下是兩種方案的詳細說明及示例&#xff1a; 方案一&#xff1a;通過 Kubernetes Downward API 注入環境變量 原理…

1.MySQL三層結構

1.所謂安裝的Mysql數據庫&#xff0c;就是在電腦上安裝了一個數據庫管理系統&#xff08;【DBMS】database manage system&#xff09;&#xff0c;這個管理程序可以管理多個數據庫。 2.一個數據庫中可以創建多個表&#xff0c;以保存數據&#xff08;信息&#xff09;。【數據…

[深度學習]目標檢測基礎

目錄 一、實驗目的 二、實驗環境 三、實驗內容 3.1 LM_BoundBox 3.1.1 實驗代碼 3.1.2 實驗結果 3.2 LM_Anchor 3.2.1 實驗代碼 3.2.2 實驗結果 3.3 LM_Multiscale-object-detection 3.3.1 實驗代碼 3.3.2 實驗結果 四、實驗小結 一、實驗目的 了解python語…

ALOHA機器人平臺:低成本、高精度雙臂操作及其進展深度解析

原創1從感知決策到具身智能的技術躍遷與挑戰(基座模型與VLA模型)2ALOHA機器人平臺&#xff1a;低成本、高精度雙臂操作及其進展深度解析3(上)通用智能體與機器人Transformer&#xff1a;Gato和RT-1技術解析及與LLM Transformer的異同4(下)通用智能體與機器人Transformer&#x…

C++: 類 Class 的基礎用法

&#x1f3f7;? 標簽&#xff1a;C、面向對象、類、構造函數、成員函數、封裝、繼承、多態 &#x1f4c5; 更新時間&#xff1a;2025年6月15日 &#x1f4ac; 歡迎在評論區留言交流你的理解與疑問&#xff01; 文章目錄 前言一、什么是類&#xff1f;二、類的定義1.基本語法2.…

Java EE與Jakarta EE命名空間區別

在 Java 生態中&#xff0c;javax 和 jakarta 代表了 企業級 Java 規范&#xff08;Java EE/Jakarta EE&#xff09;的命名空間演進&#xff0c;核心區別在于歸屬權和管理組織的變更。以下是詳細對比&#xff1a; 1. 歷史背景 javax&#xff1a; 源自 Java EE&#xff08;Java …

2 Studying《Arm A715 Technical Reference Manual》

目錄 2. The Cortex?A715 core 2.1 Cortex?A715 core features 2.2 Cortex?A715 core confifiguration options 2.3 DSU-110 dependent features 2.4 Supported standards and specifications 2.6 Design tasks 3. Technical overview 3.1 Core components 3.2 Int…

使用Nodejs嘗試小程序后端服務編寫:簡單的待辦事項管理demo

文章目錄 結構demo步驟demo運行效果API測試(1) 添加待辦事項(2) 獲取所有待辦事項(3) 切換完成狀態(4) 刪除待辦事項 API測試-RESTClient一些其他的高級功能環境變量管理不同環境配置授權認證 測試需要登錄的接口保存響應測試腳本編寫自動化測試 bug解決 結構 嘗試寫一個簡單的…

CSS“多列布局”

多列布局是一種非常常見的布局方式&#xff0c;適用于內容豐富的頁面&#xff0c;如新聞網站、雜志或博客。 一、CSS多列布局概述 CSS多列布局允許我們將內容分成多個垂直列&#xff0c;使頁面布局更加靈活和多樣化。多列布局的主要屬性包括 ??column-count??、??col…

Pump上狙擊機制的功能優勢和實戰教學

加密世界的發展永遠伴隨著速度的革命。無論是新的 Token 上線&#xff0c;還是熱點項目的第一波流動性注入&#xff0c;搶先一步往往意味著利潤的幾何級增長。在這個講究「秒殺」與「先機」的賽道中&#xff0c;一項關鍵策略正悄然成為鏈上操作者的常規武器——狙擊&#xff08…

條件收斂的級數中項必須趨于 0,正負項抵消,但趨于 0 的速度不需要“足夠快”

條件收斂的級數中&#xff0c;項必須趨于 0&#xff0c;但趨于 0 的速度不需要“足夠快”的原因可以從以下幾個方面理解&#xff1a; 1. 收斂的必要條件&#xff1a;項趨于 0 對于任何收斂的級數&#xff08;無論是絕對收斂還是條件收斂&#xff09;&#xff0c;都必須滿足 li…