欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React?Diffing?算法完整指南(示例詳解)

 更新時間:2024年12月27日 10:51:13   作者:傻小胖  
Diffing?算法是?React?用于比較兩棵虛擬?DOM?樹差異的算法,用來確定需要更新的部分,從而最小化?DOM?操作,這篇文章主要介紹了React?Diffing?算法完整指南,需要的朋友可以參考下

React Diffing 算法完整指南

1. Diffing 算法概述

1.1 什么是 Diffing

Diffing 算法是 React 用于比較兩棵虛擬 DOM 樹差異的算法,用來確定需要更新的部分,從而最小化 DOM 操作。

1.2 基本原則

  • 不同類型的元素會產(chǎn)生不同的樹
  • 通過 key 屬性標(biāo)識哪些子元素在不同渲染中保持穩(wěn)定
  • 采用同層比較策略

2. Diffing 策略詳解

2.1 元素類型比較

// 不同類型元素比較
// 舊樹
<div>
  <Counter />
</div>
// 新樹
<span>
  <Counter />
</span>
// React 會完全刪除舊樹,重建新樹

2.2 同類型元素比較

// 同類型DOM元素比較
// 舊樹
<div className="old" title="old">
  Hello
</div>
// 新樹
<div className="new" title="new">
  World
</div>
// React 只會更新變化的屬性

2.3 組件比較

class MyComponent extends React.Component {
  render() {
    // 更新時只比較渲染結(jié)果
    return (
      <div>
        <h1>{this.props.title}</h1>
        <p>{this.props.content}</p>
      </div>
    );
  }
}

3. 列表 Diffing

3.1 無 key 的情況

// 效率較低的列表渲染
function ListWithoutKeys() {
  return (
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
  );
}
// 當(dāng)列表項變化時,React 需要重新渲染所有項

3.2 使用 key 的優(yōu)化

// 使用 key 的列表渲染
function ListWithKeys() {
  const items = [
    { id: 1, text: 'Item 1' },
    { id: 2, text: 'Item 2' },
    { id: 3, text: 'Item 3' }
  ];
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.text}</li>
      ))}
    </ul>
  );
}
// React 可以通過 key 識別哪些元素保持不變

3.3 key 的最佳實踐

// 不推薦:使用索引作為 key
const BadList = () => (
  <ul>
    {items.map((item, index) => (
      <li key={index}>{item.text}</li>
    ))}
  </ul>
);
// 推薦:使用穩(wěn)定的唯一標(biāo)識作為 key
const GoodList = () => (
  <ul>
    {items.map(item => (
      <li key={item.id}>{item.text}</li>
    ))}
  </ul>
);

4. Diffing 算法實現(xiàn)原理

4.1 樹的遍歷策略

function diffTree(oldTree, newTree) {
  if (oldTree === null) {
    // 插入新節(jié)點
    return createNode(newTree);
  }
  if (newTree === null) {
    // 刪除舊節(jié)點
    return null;
  }
  if (oldTree.type !== newTree.type) {
    // 替換節(jié)點
    return createNode(newTree);
  }
  // 更新現(xiàn)有節(jié)點
  updateNode(oldTree, newTree);
  // 遞歸處理子節(jié)點
  diffChildren(oldTree.children, newTree.children);
}

4.2 子節(jié)點比較算法

function diffChildren(oldChildren, newChildren) {
  // 第一輪:處理更新的節(jié)點
  for (let i = 0; i < Math.min(oldChildren.length, newChildren.length); i++) {
    diff(oldChildren[i], newChildren[i]);
  }
  // 處理新增的節(jié)點
  if (newChildren.length > oldChildren.length) {
    newChildren.slice(oldChildren.length).forEach(child => {
      create(child);
    });
  }
  // 處理刪除的節(jié)點
  if (oldChildren.length > newChildren.length) {
    oldChildren.slice(newChildren.length).forEach(child => {
      remove(child);
    });
  }
}

5. 性能優(yōu)化策略

5.1 避免不必要的渲染

class OptimizedComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    // 只在必要時更新
    return this.props.value !== nextProps.value;
  }
  render() {
    return <div>{this.props.value}</div>;
  }
}
// 使用 React.memo 優(yōu)化函數(shù)組件
const MemoizedComponent = React.memo(function MyComponent(props) {
  return <div>{props.value}</div>;
});

5.2 列表優(yōu)化

// 使用 key 和 memo 優(yōu)化列表渲染
const OptimizedListItem = React.memo(({ item }) => (
  <li>{item.text}</li>
));
function OptimizedList({ items }) {
  return (
    <ul>
      {items.map(item => (
        <OptimizedListItem 
          key={item.id} 
          item={item}
        />
      ))}
    </ul>
  );
}

5.3 大型列表虛擬化

import { FixedSizeList } from 'react-window';
function VirtualizedList({ items }) {
  const Row = ({ index, style }) => (
    <div style={style}>
      {items[index].text}
    </div>
  );
  return (
    <FixedSizeList
      height={400}
      width={300}
      itemCount={items.length}
      itemSize={35}
    >
      {Row}
    </FixedSizeList>
  );
}

6. 常見問題和解決方案

6.1 key 相關(guān)問題

// 問題:key 不穩(wěn)定導(dǎo)致的重新渲染
const ProblematicList = () => (
  <ul>
    {items.map((item, i) => (
      <li key={Math.random()}>{item.text}</li> // 不要這樣做
    ))}
  </ul>
);
// 解決方案:使用穩(wěn)定的唯一標(biāo)識
const FixedList = () => (
  <ul>
    {items.map(item => (
      <li key={item.id}>{item.text}</li>
    ))}
  </ul>
);

6.2 不必要的重渲染

// 問題:父組件更新導(dǎo)致子組件不必要的重渲染
const Parent = () => {
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>
        Count: {count}
      </button>
      <Child data={data} /> // 即使 data 沒變,Child 也會重渲染
    </div>
  );
};
// 解決方案:使用 useMemo 或 React.memo
const Parent = () => {
  const [count, setCount] = useState(0);
  const memoizedData = useMemo(() => data, [data]);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>
        Count: {count}
      </button>
      <Child data={memoizedData} />
    </div>
  );
};

7. 總結(jié)

7.1 Diffing 算法要點

  • 采用同層比較策略
  • 不同類型元素產(chǎn)生不同樹
  • key 屬性的重要性
  • 組件的穩(wěn)定性

7.2 優(yōu)化建議

  • 合理使用 key
  • 避免不必要的嵌套
  • 使用不可變數(shù)據(jù)結(jié)構(gòu)
  • 適當(dāng)使用 memo 和 useMemo
  • 大列表考慮虛擬化

7.3 最佳實踐

  • 保持組件的純粹性
  • 合理拆分組件
  • 正確使用 key
  • 避免深層組件樹
  • 及時進(jìn)行性能優(yōu)化

8. 經(jīng)典面試題

1.react/vue中的key有什么作用? (key的內(nèi)部原理是什么?)
2.為什么遍歷列表時,key最好不要用index?
1. 虛擬DOM中key的作用:
簡單的說:key是虛擬DOM對象的標(biāo)識,在更新顯示時key起著極其重要的作用。
詳細(xì)的說:當(dāng)狀態(tài)中的數(shù)據(jù)發(fā)生變化時,react會根據(jù)【新數(shù)據(jù)]生成[新的虛擬DOM], 隨后React進(jìn)行【新虛擬DOM]與【舊虛擬DOM]的diff 比較,比較規(guī)則如下:
a,舊虛擬DOM中找到了與新虛擬DOM相同的key:
(1).若虛擬DOM中內(nèi)容沒變,直接使用之前的真實DOM
(2).若虛擬DOM中內(nèi)容變了,則生成新的真實DOM,隨后替換掉頁面中之前的真實DOM
b.舊虛擬DOM中未找到與新虛擬DOM相同的key 根據(jù)數(shù)據(jù)創(chuàng)建新的真實DOM,隨后渲染到到頁面
2.用indexf作 key可能會引發(fā)的問題:

1.若對數(shù)據(jù)進(jìn)行:逆序添加,逆序刪除等破壞順序操作: 會產(chǎn)生沒有必要的真實DOM更新 ==>界面效果沒問題,但效半低。
2.如果結(jié)構(gòu)中還包含輸入類的DOM: 會產(chǎn)生錯誤DOM更新 ==>界面有問題。
3.注意!如果不存在對數(shù)據(jù)的逆序添加、逆序刪除等破壞順序操作,僅用于渲染列表用于展示,使用index作為key是沒有問題的。 

3.開發(fā)中如何選擇key?:

1.最好使用每條數(shù)據(jù)的唯一標(biāo)識作為key,比如id、手機(jī)號、身份證號、學(xué)號等唯一值。
2.如果確定只是簡單的展示數(shù)據(jù),用index也是可以的。

到此這篇關(guān)于React Diffing 算法完整指南的文章就介紹到這了,更多相關(guān)React Diffing 算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • react中使用video.js的踩坑記錄

    react中使用video.js的踩坑記錄

    這篇文章主要介紹了react中使用video.js的踩坑記錄,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • React中的合成事件是什么原理

    React中的合成事件是什么原理

    React 中的事件,是對原生事件的封裝,叫做合成事件。這篇文章主要通過幾個簡單的示例為大家詳細(xì)介紹一下React中的合成事件,感興趣的可以了解一下
    2023-02-02
  • React組件間傳值及跨組件通信詳解

    React組件間傳值及跨組件通信詳解

    這篇文章主要介紹了React組件間傳值及跨組件通信的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-09-09
  • react-router browserHistory刷新頁面404問題解決方法

    react-router browserHistory刷新頁面404問題解決方法

    本篇文章主要介紹了react-router browserHistory刷新頁面404問題解決方法,非常具有實用價值,需要的朋友可以參考下
    2017-12-12
  • React Hooks獲取數(shù)據(jù)實現(xiàn)方法介紹

    React Hooks獲取數(shù)據(jù)實現(xiàn)方法介紹

    這篇文章主要介紹了react hooks獲取數(shù)據(jù),文中給大家介紹了useState dispatch函數(shù)如何與其使用的Function Component進(jìn)行綁定,實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • React?Virtual?DOM前端框架全面分析

    React?Virtual?DOM前端框架全面分析

    這篇文章主要為大家介紹了React?Virtual?DOM前端框架全面分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • React解析html 標(biāo)簽的方法

    React解析html 標(biāo)簽的方法

    在React中,解析HTML標(biāo)簽通常是使用JSX(JavaScript XML)語法的一部分,這篇文章主要介紹了React 用來解析html 標(biāo)簽的方法,本文通過示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • React+Koa實現(xiàn)文件上傳的示例

    React+Koa實現(xiàn)文件上傳的示例

    這篇文章主要介紹了React+Koa實現(xiàn)文件上傳的示例,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下
    2021-04-04
  • React實現(xiàn)生成和導(dǎo)出Word文檔的方法詳解

    React實現(xiàn)生成和導(dǎo)出Word文檔的方法詳解

    React是一個流行的JavaScript庫,用于構(gòu)建現(xiàn)代前端應(yīng)用程序,本文將深入探討如何在React中生成和導(dǎo)出Word文檔,感興趣的小伙伴可以學(xué)習(xí)一下
    2023-09-09
  • react項目打包后點擊index.html頁面出現(xiàn)空白的問題

    react項目打包后點擊index.html頁面出現(xiàn)空白的問題

    這篇文章主要介紹了react項目打包后點擊index.html頁面出現(xiàn)空白的問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06

最新評論