自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深度掌握 ReactJS 高級概念:前端開發(fā)者必備

開發(fā) 前端
ReactJS 的核心運(yùn)行機(jī)制就是把 JSX 轉(zhuǎn)成 ??React.createElement()?? 調(diào)用,再把這些 “React Element” 組成虛擬 DOM。

這篇文章匯總了 ReactJS 中值得深入研究的高級概念。讀完后,不僅在前端面試中能更胸有成竹,還能自行開發(fā)一個(gè)類似 ReactJS 的 UI 庫。

目錄

  1. Rendering 的含義與過程
  2. Re-rendering 發(fā)生的機(jī)制及原因
  3. Virtual DOM 的原理
  4. Reconciliation 算法的運(yùn)行方式
  5. ReactJS 的性能優(yōu)化方案

1. 什么是 Rendering?它是如何進(jìn)行的?

在 React 中,我們常提到 “渲染(Rendering)”。本質(zhì)上,它是把 JSX 或通過 React.createElement() 生成的元素轉(zhuǎn)換為實(shí)際的 DOM 節(jié)點(diǎn),讓頁面在瀏覽器中展現(xiàn)出來。

JSX 與 React.createElement()

JSX(JavaScript XML)是一種 React 引入的語法糖。瀏覽器只能理解 JavaScript,所以 JSX 需要先經(jīng)過 Babel 編譯成 React.createElement() 的調(diào)用,才會生成所謂的 “React Element”(一個(gè)純粹的 JavaScript 對象)。

示例:

例 1

// JSX 寫法
const jsx = <h1>Hello, React!</h1>;

// Babel 轉(zhuǎn)換后
const element = React.createElement("h1", null, "Hello, React!");

image.png

例 2

const Jsx = <h1 className="title">Hello, React!</h1>;

// Babel 轉(zhuǎn)換后
const element = React.createElement("h1", { className: "title" }, "Hello, React!");

例 3

<div>
  <h1>Hello</h1>
  <p>Welcome to React</p>
</div>

// Babel 轉(zhuǎn)換后

const element = React.createElement(
  "div",
  null,
  React.createElement("h1", null, "Hello"),
  React.createElement("p", null, "Welcome to React")
);

例 4

const Jsx = <Card data = {cardData} />

// Babel 轉(zhuǎn)換后
const element = React.createElement(Card, { data: cardData })

React.createElement(type, props, ...children) 會返回一個(gè)描述 DOM 結(jié)構(gòu)的 JS 對象,如:

{
  type: "h1",
  props: {
    className: "title",
    children: "Hello, React!"
  },
  key: null,
  ref: null,
  ...
}

React 最終會根據(jù)這些對象來構(gòu)造真實(shí) DOM。

初次渲染(Initial Rendering)

初次渲染的流程大致是:

  1. React 組件(函數(shù)式/類)返回 JSX
  2. Babel 將其轉(zhuǎn)換為 React Element
  3. React 構(gòu)建出一份虛擬的 DOM 結(jié)構(gòu)(Virtual DOM)
  4. React 將虛擬 DOM 與真實(shí) DOM 同步,頁面上出現(xiàn)相應(yīng)的節(jié)點(diǎn)

大型應(yīng)用通常有成百上千個(gè)組件嵌套,最終 React 會構(gòu)建出巨大的虛擬 DOM 樹,再將其 “映射” 到真實(shí) DOM。初次加載時(shí)生成的真實(shí) DOM 較多,耗時(shí)也更多。

2. 什么是 Re-rendering,組件何時(shí)會重新渲染?

Re-rendering 指組件為了更新 UI,會再次執(zhí)行渲染過程。React 只在需要時(shí)重新渲染,而不是盲目全量刷新,以提高效率。

觸發(fā)重新渲染的場景

  • State 變化
    當(dāng) useState 或 this.setState 更新了 state,組件會重新渲染。
import React, { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  console.log("Counter Re-Rendered!");

  return (
    <div>
      <h1>Count: {count}</h1>
      <button notallow={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default Counter;
  • Props 改變
    如果父組件傳遞的新 props 和舊 props 不同,子組件會重新渲染。
function Parent() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <Child count={count} />
      <button notallow={() => setCount(count + 1)}>Update Count</button>
    </div>
  );
}


function Child({ count }) {
  console.log("Child Re-Rendered!");

  return <h1>Count: {count}</h1>;
}

export default Parent;
  • 父組件重渲染
    只要父組件重新渲染,即使子組件的 props 沒變,子組件也默認(rèn)跟著渲染。
function Parent() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <Child />
      <button onClick={() => setCount(count + 1)}>Re-Render Parent</button>
    </div>
  );
}

function Child() {
  console.log("Child Re-Rendered!");
  return <h1>Hello</h1>;
}

點(diǎn)按鈕后,父組件因?yàn)?state 改變而重渲染,Child 也跟著渲染。如果不想子組件重復(fù)渲染,可以使用 React.memo(Child),阻止不必要的更新。

React 18+ 中的嚴(yán)格模式雙重渲染

在開發(fā)模式下,<React.StrictMode> 會讓組件在初始化時(shí)執(zhí)行兩次渲染,以檢測副作用。這在生產(chǎn)環(huán)境不會觸發(fā),只需要知道這是為了幫助開發(fā)調(diào)試即可。

import React from "react";
import ReactDOM from "react-dom";

function App() {
  console.log("Component Rendered!");
  return <h1>Hello</h1>;
}

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

3. 理解 Virtual DOM

虛擬 DOM(V-DOM)是 React 在內(nèi)存中維護(hù)的一份輕量級 DOM 結(jié)構(gòu),能顯著減少對真實(shí) DOM 的頻繁操作。

  • 真實(shí) DOM 操作昂貴
  • 虛擬 DOM 先在內(nèi)存中對比,再只更新有差異的地方

工作流程

  • 生成初始虛擬 DOM
  • 數(shù)據(jù)或 props 變動時(shí),生成新的虛擬 DOM
  • 對比新舊虛擬 DOM 的差別(Diff 過程)
  • 有變化的地方才更新真實(shí) DOM

這種按需更新機(jī)制提升了性能。比方說文本從 “Count: 0” 變成 “Count: 1”,React 只會修改文本內(nèi)容,而不會重新創(chuàng)建整個(gè) <h1> 標(biāo)簽。

4. Reconciliation:React 的高效更新算法

Reconciliation 是 React 用來高效處理 DOM 更新的過程,核心是 Diff 算法。

Diff 規(guī)則

  • 不同類型的元素
    如果 type 變了(比如從 <h1> 變 <p>,或從 Card 組件變成 List 組件),React 會銷毀原節(jié)點(diǎn)并新建節(jié)點(diǎn)。
function App({ showText }) {
  return showText ? <h1>Hello</h1> : <p>Hello</p>;
}
  • 相同類型的元素
    如果 type 相同,只更新變更部分。例如修改屬性或文本內(nèi)容。
function App({ text }) {
  return <h1 className="title">{text}</h1>;
}

將 text 從 "Hello" 改為 "World" 會使 React 僅更新文本。

  • 列表中的 Key
    當(dāng)使用 map() 渲染列表時(shí),務(wù)必給每個(gè)項(xiàng)加唯一 key,這樣 React 才能跟蹤列表項(xiàng),做最小化更新。如果沒有 key(或 key 不唯一),React 很可能重渲染整個(gè)列表,導(dǎo)致性能浪費(fèi)。

代碼錯(cuò)誤(無key) → diff 效率低

function List({ items }) {
  return (
    <ul>
      {items.map((item) => (
        <li>{item}</li>
      ))}
    </ul>
  );
}

如果在開始時(shí)添加了一個(gè)新項(xiàng)目,React 會重新渲染所有 <li> 元素,這樣做很慢,因?yàn)?React 無法跟蹤沒有鍵的單個(gè)項(xiàng)目。

良好代碼(key) → 優(yōu)化對賬

function List({ items }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

5. ReactJS 的性能優(yōu)化技巧

5.1 React.memo():防止不必要的子組件重復(fù)渲染

在父組件刷新而子組件 props 未變的情況下,React.memo(Child) 能阻止子組件重復(fù)渲染。

const ChildComponent = React.memo(({ count }) => {
  console.log("Child render");
  return <h2>Count: {count}</h2>;
});

只要 count 沒變化,就不會重復(fù)渲染。

5.2 useMemo():緩存昂貴計(jì)算結(jié)果

如果某個(gè)函數(shù)計(jì)算量大且多次使用相同參數(shù),可以用 useMemo 緩存結(jié)果,避免重復(fù)計(jì)算。

function expensiveComputation(num) {
  console.log("Computing...");
  return num * 2; 
}

function App() {
  const [number, setNumber] = useState(5);
  const memoizedValue = useMemo(() => expensiveComputation(number), [number]);

  // 每次渲染,只要 number 不變,就不會重復(fù)執(zhí)行 expensiveComputation
  return <h2>Computed Value: {memoizedValue}</h2>;
}

5.3 useCallback():緩存函數(shù)引用,減少子組件不必要的渲染

React 每次渲染都會重新創(chuàng)建函數(shù)。如果子組件接收函數(shù)作為 props,默認(rèn)會認(rèn)為 props 變了,進(jìn)而觸發(fā)子組件渲染。用 useCallback() 可以讓函數(shù)在依賴不變時(shí)保持相同引用。

function App() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log("Button clicked");
  }, []);

  return (
    <div>
      <ChildComponent onClick={handleClick} />
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

這樣 ChildComponent 不會因?yàn)?nbsp;onClick prop 每次都換新函數(shù)而被動重渲染。

總結(jié)

ReactJS 的核心運(yùn)行機(jī)制就是把 JSX 轉(zhuǎn)成 React.createElement() 調(diào)用,再把這些 “React Element” 組成虛擬 DOM。通過比較新舊虛擬 DOM 的差異(Reconciliation),React 能用最小代價(jià)更新真實(shí) DOM?;谶@個(gè)原理,就能延伸出許多優(yōu)化策略,比如:

  • 使用 React.memo 防止子組件反復(fù)刷新
  • 通過 useMemo、useCallback 緩存耗時(shí)操作及函數(shù)引用
  • 在列表中使用 key,避免不必要的遍歷和重繪

這些技巧能夠在大規(guī)模項(xiàng)目中讓性能和可維護(hù)性都大幅提升,也是真正掌握 ReactJS 的關(guān)鍵所在。

責(zé)任編輯:武曉燕 來源: 大遷世界
相關(guān)推薦

2021-12-15 20:06:48

ReactJSSentry開發(fā)者

2019-03-12 10:38:18

前端開發(fā)Nginx

2021-04-08 10:40:24

前端工具代碼

2013-10-08 10:42:27

前端開發(fā)開發(fā)

2013-08-08 10:26:08

前端開發(fā)Web

2021-04-01 07:52:57

前端開發(fā)技術(shù)熱點(diǎn)

2025-01-23 13:58:17

2025-03-11 11:00:00

后端前端開發(fā)

2024-08-09 15:01:00

2012-02-13 10:21:11

Skala PreviiOS應(yīng)用

2023-11-30 15:30:19

Python編程語言

2017-01-16 13:15:19

前端開發(fā)者清單

2014-07-08 10:30:59

開發(fā)者開發(fā)語言

2014-03-14 11:44:28

安卓開發(fā)者Android開發(fā)

2014-02-01 21:31:10

JavaScriptJS框架

2014-04-01 13:50:28

安卓Android開發(fā)者

2013-07-19 09:47:57

White ElephHadoopLinkedIn

2011-03-01 13:10:06

WebjQueryHTML 5

2017-10-23 09:27:47

2022-09-15 17:08:20

JavaScripWeb開發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號