」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 反應虛擬 DOM

反應虛擬 DOM

發佈於2024-11-08
瀏覽:106

Introduction

Hi, Gleb Kotovsky is here!

Today I wanna talk about Virtual DOM, specifically - React Virtual DOM

So, the virtual DOM (Virtual Document Object Model) is a cool programming idea that keeps a "virtual" version of a user interface in memory. This version syncs up with the browser's DOM (Document Object Model) using a library.

You’ll find the virtual DOM is a big part of many JavaScript front-end frameworks, and it’s one of the reasons they’re so efficient. In this article, we're going to dive into how the virtual DOM works in React and why it’s important for the library.

What is the DOM?

When a webpage loads in a browser, it typically receives an HTML document from the server. The browser then builds a logical, tree-like structure from this HTML to render the requested page for the user. This structure is known as the DOM.

The Document Object Model (DOM) represents a logical tree that describes a document. Each branch of the tree ends in a node , which contains an object . Because the browser parses the document into this tree structure, there is a need for methods that allow for programmatic access to the tree, enabling modifications to the document's structure, style, or content. This necessity led to the development of the DOM API, which offers these methods for manipulating the nodes representing the elements in the tree.

React Virtual DOM

React's Virtual DOM Implementation

To optimize re-rendering in websites and applications, many JavaScript frameworks offer different strategies. However, React employs the concept of the virtual DOM.

The virtual DOM in React represents the user interface as a "virtual" tree structure, where each element is a node containing an object. This representation is maintained in memory and synchronized with the browser's DOM through React's React DOM library.

When React and many other famous frameworks uses Virtual DOM, Svelte meanwhile has no Virtual DOM. Svelte works directly with the DOM in the browser and modifies it as needed.

Here's a simple example to illustrate the Virtual DOM in a React component:

import React, { useState } from 'react';

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

  const increment = () => setCount(count   1);

  return (
    

Count: {count}

); }

In this example:

  • The component renders a counter and a button.
  • When the button is clicked, the state is updated, prompting React to create a new Virtual DOM tree.
  • The diffing algorithm checks what has changed (only the count) and updates the real DOM accordingly.

After the component is first rendered and the state is count: 0, the actual DOM will look like this:

Counter

Count: 0

How the Virtual DOM Works:

Here's a simple example to illustrate the Virtual DOM in a React component, starting with the component definition:

1. Component Definition

import React, { useState } from 'react';

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

  const increment = () => setCount(count   1);

  return (
    

Counter

Count: {count}

); }

2. Initial Render Process

2.1 Component Initialization

When the component is first rendered, React calls the Counter function.

2.2 State Initialization

useState(0) initializes the component's state to 0.

2.3 Creating the Virtual DOM

React generates a Virtual DOM tree using the component's returned JSX structure. This tree is a lightweight representation of the UI.

For the initial render, the Virtual DOM might look like this:

{
  "type": "div",
  "props": {
    "children": [
      { "type": "h1", "props": { "children": "Counter" } },
      { "type": "p", "props": { "children": "Count: 0" } },
      { "type": "button", "props": { "children": "Increment" } }
    ]
  }
}

2.4 Updating the Real DOM

React then takes this Virtual DOM and calculates what changes need to be made to the actual DOM. In this case, it creates the following HTML:

Counter

Count: 0

3. User Interaction

When a user clicks the "Increment" button, the following steps occur:

3.1 Event Handling

The button's onClick event triggers the increment function, calling setCount(count 1).

3.2 State Update

The component's state is updated, which causes React to know that it needs to re-render the component with the new state.

4. Re-render Process

4.1 Component Re-invocation

React calls the Counter function again due to the state change.

4.2 New Virtual DOM Creation

A new Virtual DOM tree is created reflecting the updated state:

{
  "type": "div",
  "props": {
    "children": [
      { "type": "h1", "props": { "children": "Counter" } },
      { "type": "p", "props": { "children": "Count: 1" } },
      { "type": "button", "props": { "children": "Increment" } }
    ]
  }
}

4.3 Diffing the Virtual DOM

React compares the new Virtual DOM with the previous Virtual DOM. It identifies what has changed—in this case, the text in the

tag has changed from "Count: 0" to "Count: 1".

4.4 Reconciliation

Only the parts of the real DOM that have changed are updated. In this case, React updates the real DOM to reflect the new count:

Counter

Count: 1

5. Performance Optimization

5.1 Batching Updates

If multiple state updates occur in rapid succession (e.g., multiple button clicks), React may batch these updates together for efficiency, minimizing the number of re-renders and DOM updates.

Common Problems with React Virtual DOM and How to Avoid Them

  1. Performance Bottlenecks
    • Issue: Excessive re-renders can occur even with the Virtual DOM.
    • Solution: Use React.memo to memoize functional components.
const MyComponent = React.memo(({ value }) => {
  console.log('Rendered: ', value);
  return 
{value}
; });

Legacy: Use shouldComponentUpdate in class components:

class MyClassComponent extends React.Component {
  shouldComponentUpdate(nextProps) {
    return nextProps.value !== this.props.value;
  }

  render() {
    return 
{this.props.value}
; } }
  1. Inefficient Key Management
    • Issue: Improper handling of keys in lists can lead to bugs.
    • Solution: Use unique and stable keys, not array indices.
   const items = ['Apple', 'Banana', 'Cherry'];
      return (
        
    {items.map(item => (
  • {item}
  • // Prefer unique values as keys ))}
);
  1. Overusing State and Updates
    • Issue: Too many state updates lead to performance issues.
    • Solution: Combine related states
const [state, setState] = useState({
  name: '',
  age: 0,
});

const updateAge = (newAge) => {
  setState(prevState => ({ ...prevState, age: newAge }));
};

  1. Using Inline Functions
    • Issue: Inline functions create new instances on every render.
    • Solution: Use useCallback to memoize functions.
const increment = useCallback(() => {
  setCount(c => c   1);
}, []); // Only recreate the function if dependencies change

  1. Deep Component Trees
    • Issue: Deeply nested components trigger multiple re-renders.
    • Solution: Use context.
const CountContext = React.createContext();

const ParentComponent = () => {
  const [count, setCount] = useState(0);

  return (
    
  );
};

const ChildComponent = () => {
  const { count, setCount } = useContext(CountContext);
  return 
setCount(count 1)}>Count: {count}
; };
  1. Excessive Re-renders Due to Parent Component Updates
    • Issue: Child components re-render when parents update.
    • Solution: Memoize child components.
const ChildComponent = React.memo(({ count }) => {
  return 
Count: {count}
; });
  1. Inefficient Rendering of Expensive Components
    • Issue: Expensive components can slow down the app.
    • Solution: Use React.lazy and React.Suspense.
const LazyComponent = React.lazy(() => import('./LazyComponent'));

const App = () => (
  Loading...}>
    
);

  1. Managing Side Effects
    • Issue: Side effects can cause bugs if not managed properly.
    • Solution: Use useEffect with proper dependencies.
useEffect(() => {
  const timer = setTimeout(() => {
    console.log('Time elapsed');
  }, 1000);

  return () => clearTimeout(timer); // Cleanup on unmount or if dependencies change
}, [dependencies]); // Replace with actual dependency

  1. Confusion Between State and Props
    • Issue: Misunderstanding when to use state vs. props.
    • Solution: Use props for externally managed data and state for local data.
const ParentComponent = () => {
  const [name, setName] = useState('John');

  return ;
};

const ChildComponent = ({ name, setName }) => (
  

{name}

);
  1. Neglecting Accessibility
    • Issue: Accessibility concerns can be ignored.
    • Solution: Use semantic HTML and accessibility tools.
const AccessibleButton = () => (
  
);

Conclusion

To wrap things up, React’s Virtual DOM is a fantastic feature that really boosts the performance of your web applications. By creating a lightweight version of the actual DOM, React can make updates more efficiently, avoiding the slowdowns that come with direct DOM manipulation.

That said, it’s important to watch out for common issues like excessive re-renders, poor key management in lists, and mixing up state and props. By keeping some best practices in mind—like using memoization, deploying context for handling state, and managing side effects wisely—you can get the most out of React and keep your apps running smoothly.

Happy hacking!

Resources

1) https://www.geeksforgeeks.org/reactjs-virtual-dom/
2) https://svelte.dev/blog/virtual-dom-is-pure-overhead
3) https://refine.dev/blog/react-virtual-dom/#introduction

版本聲明 本文轉載於:https://dev.to/gaundergod/react-virtual-dom-45al?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 用於建構生成式人工智慧應用程式的開源框架
    用於建構生成式人工智慧應用程式的開源框架
    有許多令人驚嘆的工具可以幫助建立生成式人工智慧應用程式。但開始使用新工具需要時間學習和練習。 因此,我創建了一個儲存庫,其中包含用於建立生成人工智慧應用程式的流行開源框架的範例。 這些範例也展示瞭如何將這些框架與 Amazon Bedrock 結合使用。 您可以在這裡找到存儲庫: https:...
    程式設計 發佈於2024-11-08
  • 如何在 C# 中從 MySQL 資料庫載入和顯示映像?
    如何在 C# 中從 MySQL 資料庫載入和顯示映像?
    如何從MySQL 資料庫擷取與顯示影像如何從MySQL 資料庫擷取與顯示影像從MySQL 資料庫擷取影像到PictureBox 控制項中需要採用具有正確位元組的特定方法數組處理。以下步驟示範了這個過程:將映像插入 MySQL 資料庫使用 MySql.Data.MySqlClient 庫進行 MySQ...
    程式設計 發佈於2024-11-08
  • 引用計數與追蹤垃圾收集
    引用計數與追蹤垃圾收集
    你好,Mentes Tech! 您知道記憶體釋放上下文中的引用計數和引用追蹤是什麼嗎? 引用追蹤(或追蹤垃圾收集)和引用計數(引用計數)之間的區別在於每種技術用於識別和釋放不存在的物件記憶體的方法。使用時間更長。 我將解釋每一個,然後強調主要差異。 引用計數(引用計數) 工作...
    程式設計 發佈於2024-11-08
  • 單行SQL查詢失敗時如何傳回預設值?
    單行SQL查詢失敗時如何傳回預設值?
    單行查詢失敗時傳回預設值在執行SQL查詢以取得特定資料時,常會遇到沒有對應行的情況存在。為了避免傳回空結果,您可能需要提供預設值。 考慮以下 SQL 語句,該語句檢索流的下一個計劃項目:SELECT `file` FROM `show`, `schedule` WHERE `channel` = ...
    程式設計 發佈於2024-11-08
  • Cypress 自動化可訪問性測試:綜合指南
    Cypress 自動化可訪問性測試:綜合指南
    介紹 輔助功能是 Web 開發的重要方面,確保所有使用者(包括殘障人士)都可以與您的 Web 應用程式有效互動。自動化可訪問性測試有助於在開發過程的早期識別和解決可訪問性問題。在這篇文章中,我們將探討如何使用 Cypress 實現自動化可訪問性測試,利用 cypress-axe 等...
    程式設計 發佈於2024-11-08
  • 為什麼 Javascript 和 jQuery 找不到 HTML 元素?
    為什麼 Javascript 和 jQuery 找不到 HTML 元素?
    Javascript 和jQuery 無法偵測HTML 元素當嘗試使用Javascript 和jQuery 操作HTML 元素時,您可能會遇到令人沮喪的問題未定義的元素。當腳本嘗試存取 HTML 文件中尚未定義的元素時,就會發生這種情況。 在提供的 HTML 和腳本中,「script.js」檔案在其...
    程式設計 發佈於2024-11-08
  • Polars 與 Pandas Python 資料幀的新時代?
    Polars 與 Pandas Python 資料幀的新時代?
    北極熊與熊貓:有什麼區別? 如果您一直在關注 Python 的最新發展,您可能聽說過 Polars,一個用於處理資料的新程式庫。雖然 pandas 長期以來一直是首選庫,但 Polars 正在掀起波瀾,尤其是在處理大型資料集方面。那麼,Polars 有什麼大不了的呢?它和熊貓有什麼...
    程式設計 發佈於2024-11-08
  • 使用 Golang 使用 Api 閘道模式建立基本的微服務線上商店後端 - 第 1 部分
    使用 Golang 使用 Api 閘道模式建立基本的微服務線上商店後端 - 第 1 部分
    Introduction Hey, fellow developers! ? Ever thought about building a microservices architecture but felt overwhelmed by where to start? Worry...
    程式設計 發佈於2024-11-08
  • 如何有效率地尋找多個Python清單中的相交元素?
    如何有效率地尋找多個Python清單中的相交元素?
    識別多個Python列表中的共享元素在Python中,提取兩個列表的交集可以使用set.intersection()函數來實現。然而,確定多個清單的交集變得更加複雜。這是一個有效識別多個清單之間共享元素的解決方案:答案中提供的公式set.intersection(*map(set,d)) 提供了一種...
    程式設計 發佈於2024-11-08
  • 如何取得 Openpyxl 中單元格的原始值,即使它包含公式?
    如何取得 Openpyxl 中單元格的原始值,即使它包含公式?
    如何在Openpyxl 中擷取實際儲存格值使用openpyxl 存取Excel 中的儲存格值時,您可能會遇到顯示的值與儲存在Openpyxl中的實際值之間的差異單元格(如果單元格包含公式)。這是因為 openpyxl 通常會解釋公式並檢索計算結果。 要擷取實際儲存格值(包括公式),可以在載入工作簿時...
    程式設計 發佈於2024-11-08
  • Go 中如何有效率地將 UTF-8 字串轉換為位元組數組?
    Go 中如何有效率地將 UTF-8 字串轉換為位元組數組?
    將UTF-8 字串轉換為位元組陣列解組JSON 需要位元組切片輸入,而字串在Go 中儲存為UTF-8 。本文探討了 UTF-8 字串到位元組數組的高效轉換。 直接轉換Go 允許將字串轉換為位元組切片,建立字串位元組的副本:s := "some text" b := []byte(...
    程式設計 發佈於2024-11-08
  • 我如何使用 dpdm 修復 Redux 中的循環依賴錯誤
    我如何使用 dpdm 修復 Redux 中的循環依賴錯誤
    打破混亂循環:Redux 循環依賴之旅 最近,我在 Redux 程式碼庫中偶然發現了一個讓我摸不著頭緒的錯誤。如果您曾經在測試套件拋出毫無意義的錯誤時感到突然的混亂,您就會知道這種感覺。這是發生的事情以及我最終如何發現(並解決)問題的。 循環依賴到底是什麼? 當兩...
    程式設計 發佈於2024-11-08
  • 我可以在單一 MySQLi 語句中準備多個查詢嗎?
    我可以在單一 MySQLi 語句中準備多個查詢嗎?
    在單一 MySQLi 語句中準備多個查詢不可能在單一 MySQLi 語句中準備多個查詢。每個 mysqli_prepare() 呼叫只能準備一個查詢。 執行多個查詢的替代方法如果您需要一次執行多個查詢,您可以建立並為每個查詢執行單獨的mysqli_prepare() 語句。 $stmtUser = ...
    程式設計 發佈於2024-11-08
  • 在 Golang 中安全使用 Map:宣告和初始化的差異
    在 Golang 中安全使用 Map:宣告和初始化的差異
    介绍 本周,我正在为 golang 开发一个 API 包装器包,它处理发送带有 URL 编码值的 post 请求、设置 cookie 以及所有有趣的东西。但是,当我构建主体时,我使用 url.Value 类型来构建主体,并使用它来添加和设置键值对。然而,我在某些部分遇到了有线零指针...
    程式設計 發佈於2024-11-08
  • 下一個目標
    下一個目標
    我剛剛完成了我的論文,並以令人印象深刻的分數9.1/10,我對此感到非常自豪。提交給 REV-ECIT 2024 的截止日期是 9 月 30 日,目的是將我的論文變成已發表的期刊文章。目前我正在博士生導師的支持下完善我的工作,非常感謝他的指導。 ? 另外,在與SA進行了很長時間的面試後,提出了一...
    程式設計 發佈於2024-11-08

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3