React 面試 15 個核心技術問題 Virtual DOM 原理與常見問答

me
林彥成
2021-05-07 | 9 min.
文章目錄
  1. 1. React 面試必考的核心觀念有哪些?
    1. 1.1. 什麼是 React.js?其核心優勢為何?
    2. 1.2. 什麼是元件? 為什麼元件的概念對 React 來說很重要?
    3. 1.3. Props 和 State 差別在哪?
    4. 1.4. 選擇一個曾經在專案中用過的元件週期,並介紹你是怎麼使用的?
    5. 1.5. Class 跟 Functional 元件的差別? 該怎麼選擇?
    6. 1.6. 什麼是 React 中的 Events?
    7. 1.7. 什麼是 JSX?
    8. 1.8. Virtual DOM 原理與運作方式
    9. 1.9. 你會怎麼 Debug 用 React 寫出來的網頁應用? 用哪些工具?
    10. 1.10. React 跟 React Native 差別在哪?
    11. 1.11. 用 React 的優點是什麼?
    12. 1.12. React 有什麼缺點和限制?
    13. 1.13. Redux 與狀態管理面試解析
    14. 1.14. 使用 Redux 的優點是什麼?
    15. 1.15. 為什麼你會想選擇 React?
    16. 1.16. React 生命週期面試重點:從 Class 到 Hooks
    17. 1.17. 什麼是 Reconciliation?
    18. 1.18. 什麼是 HOC (Higher-Order Components)?
    19. 1.19. React 中的 Portals 是做什麼用的?
    20. 1.20. React v16 錯誤邊界 (Error Boundaries) 是什麼?
    21. 1.21. React 中要怎麼實作 Props 相關檢查?
    22. 1.22. 如何在頁面載入時自動 focus 在輸入框上?
  2. 2. FAQ:React 面試與核心觀念常見問題
    1. 2.1. Q1:Virtual DOM 真的能讓網頁變快嗎?有沒有什麼誤區?
    2. 2.2. Q2:Hooks 出現後,還有必要在大型專案中使用 Redux 嗎?
    3. 2.3. Q3:如何向面試官解釋 Reconciliation (調和) 的運作流程?
    4. 2.4. 同場加映

React 面試必考的核心觀念有哪些?

準備 React 面試題目 的核心在於理解「為什麼使用 React」。高品質的 React JS 觀念解析 應包含:1. Virtual DOM 原理:透過記憶體中的 DOM 快照與 Reconciliation (調和) 演算法,將多次更新 batch 處理以減少 re-flow;2. React 生命週期面試:掌握 Render 與 Commit 兩大階段,及 Hooks 時代 useEffect 的應用;3. Props 與 State:釐清資料流向與不可變性 (Immutability);4. 進階架構:如 HOC (高階元件) 的邏輯重用與錯誤邊界 (Error Boundaries) 的防禦。掌握這些技術細節與 Redux 與狀態管理面試 邏輯,能展現您對前端效能優化與高品質程式碼維護的專業深度。


在準備前端開發職位的過程中,掌握核心的 React 面試題目 是成功錄取的關鍵。本文參考了國外熱門的 15 個關於 React JS 的面試問題,並結合實務經驗進行深度解析。無論您是初學者還是資深開發者,這些 React JS 觀念解析 都能幫助您在面試中脫穎而出。

什麼是 React.js?其核心優勢為何?

  • React.js 是一套由 Facebook 開發,專門用於實作 Web 和 Mobile 使用者介面的前端函式庫 (Library)。
  • 自 2011 年推出以來,React 憑藉其元件化架構與卓越的效能,累積了龐大的開源社群支持。
  • 其核心優點包括:提升網站效能、元件可重複使用以及豐富的生態系工具。

什麼是元件? 為什麼元件的概念對 React 來說很重要?

React 是以元件為基礎的函式庫,元件像積木一樣組成網站的使用者介面。主要有兩個好處:

  • 把使用者介面拆解成可重複使用的部分
  • 透過 React 的優化,可以做到只更新畫面中部份的元件讓效能更好

Props 和 State 差別在哪?

之前剛好寫過關於元件狀態與性質的文章,不過簡單回答:

狀態(State): 元件裡的資料,但值可以透過元件內邏輯操作而改變
性質(Props): 用來設定元件初始化的相關資料,無法透過元件內邏輯去改變

選擇一個曾經在專案中用過的元件週期,並介紹你是怎麼使用的?

週期在元件中是以函式方式顯示,在特殊階段會被觸發執行,其中 componentDidMount 就是當元件出現在畫面後會被執行。

Class 跟 Functional 元件的差別? 該怎麼選擇?

React 提供了兩種元件實做方式,更詳細的比較歡迎參考 React Class-based vs Functional Component 從特性淺談兩種寫法之異同

  • Functional component: 是最簡單的寫法,比較適合用來實作邏輯單純顯示用的元件
  • Class components: 較複雜且可以控制較多的元件週期和狀態比對

什麼是 React 中的 Events?

事件其實可以看成反應 (reactions) 的意思,還記得函式庫命名就是 React 吧。透過使用者的動作像是點擊、鍵盤輸入等來觸發使用者介面的變化,React 其實主要就是協助我們處理這些事情。

React 中的事件在撰寫上有稍微的不一樣

  1. React event handlers 會用駝峰式的命名,HTML 上面的是全小寫
  2. 透過 JSX 綁定的是 event handler 而不像 HTML 上面是綁字串

什麼是 JSX?

JSX 是 React 的語法糖,讓開發者能夠在元件中寫類似 HTML 的語法,能夠提升可閱讀性,所以如果不嫌麻煩也可以選擇不使用,雖然類似但命名和寫法還是略有差異,但透過編輯器外掛協助下其實算容易適應,像是 JSX 就需要把 class 寫成 className

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Demo() {
return (
<div>
<h1>Hello world!</h1>
</div>
);
}

function Demo() {
return React.createElement(
"div",
null,
React.createElement("h1", null, "Hello world!")
);
}

Virtual DOM 原理與運作方式

React 面試題目 中,Virtual DOM 原理 是必考題。瀏覽器載入網頁時,會將 HTML 轉為 Document Object Model (DOM)。

如果不使用 React,更新畫面通常需要直接操作 DOM,這在結構複雜時效能較差。React 的策略是透過多實作一層「影分身」—— Virtual DOM 來優化:

  1. 記憶體操作:Virtual DOM 存在於記憶體中,比對速度極快。
  2. Reconciliation (調和):透過高效演算法(如 React 16 的 Fiber)比對新舊 Virtual DOM 的差異。
  3. Batch Update:React 只是策略上改進並沒有做什麼新的花樣,透過演算法操作在記憶體中的 DOM,接著 batch 一小段時間的變化才去改變真實的 DOM,盡可能減少 re-flow 跟 re-paint 的發生而已。

你會怎麼 Debug 用 React 寫出來的網頁應用? 用哪些工具?

  • Linters (eslint, jslint)
  • Debuggers (React Developer Tools)

React 跟 React Native 差別在哪?

  • React.js 是一套協助實作 Web 和 Mobile 使用者介面的前端函式庫 (library)
  • React Native 是一套以 React 概念為基礎用來開發原生 Android 或 iOS APP 用的框架

用 React 的優點是什麼?

  • 可能會提升網站效能和使用者體驗
  • 元件可重複使用提升開發效率
  • React 生態系提供外掛工具提升專案除錯效率

React 有什麼缺點和限制?

前陣子剛好在網路上看到一篇國外文章分享,所以小編就翻譯了一篇不在大型專案導入 React.js 的 5 個原因: 關於跟著 React.js 一路成長的心得分享,簡單來說:

  • 不是完整框架只是一套 UI 函式庫所以要裝很多外部套件才能成為完整的應用
  • 要整合到傳統的 MVC 架構需要比較複雜的額外配置
  • 學習上有一定的難度,像是元件概念和 JSX 都要花時間熟悉
  • 缺乏規劃會寫出很多 boilerplate

Redux 與狀態管理面試解析

當元件架構變得複雜時,Redux 與狀態管理面試 題目就會出現。Redux 是一套除了 React 外也可以在其他 UI 的函式庫中使用的資料流管理工具,定義了資料流的規範補足了 React 在元件變多後狀態難以控管的問題,讓開發者能統一管理元件的狀態,讓程式更容易去維護和測試。

使用 Redux 的優點是什麼?

定義了一套公版資料流與程式架構,提高開發方式的可預期性、可維護性,透過 Redux 的開發者外掛開發也能夠更方便。

為什麼你會想選擇 React?

  • Virtual DOM 在某些情境下優化了效能
  • JavaScript 的開發者能在同個檔案完成所有開發動作
  • 元件能重覆利用,加速了開發速度
  • 提供 JSX 支援增加程式碼易讀性,但有沒有更好寫就見仁見智
  • 同樣的程式碼可以在 client 端和 Sever 端渲染出一樣的結果
  • Jest讓單元測試更簡單

React 生命週期面試重點:從 Class 到 Hooks

掌握 React 生命週期面試 重點,有助於展現您對元件運作流程的深度理解。元件從 Props 或 State 變化後引發改變的過程,主要分為兩大階段 Render 和 Commit,會先進行 Render 的計算後才會真的 Commit 結果到真正的 DOM 上面,Commit 前會有個 Pre-commit。

  1. Render: 在這個階段 React 能自行暫停、取消、重新這個過程
  2. Pre-commit: 文件上有出現但甚少使用的功能,有一個週期是 getSnapshotBeforeUpdate(),可以看成是一個做決定前的再次狀態確認
  3. Commit: 套用改變到瀏覽器的 DOM 上,而這是肉眼可見,也是我們較常操作的週期
    1. componentDidMount(): Mount 成功,出現在 DOM 上面
    2. componentDidUpdate(): Props 或 State 改變
    3. componentWillUnmount(): 從 DOM 上移除

什麼是 Reconciliation?

當元件 props 或是 state 改變後,React 會透過 render 的演算法來決定最終要更新到 DOM 上面的改變,這個過程就是 reconciliation。

如果是想自己手動提升效能則可以運用條件減少狀態改變:

1
2
3
4
5
6
7
8
9
10
11
getUserAddress = (user) => {
const latestAddress = user.address;
this.setState((state) => {
// 地址沒變就不用換畫面
if (state.address === latestAddress) {
return null;
} else {
return { title: latestAddress };
}
});
};

hooks 的形式則是 useMemo

1
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);

什麼是 HOC (Higher-Order Components)?

常寫 JavaScript 的開發者就會知道,function 可以 return 任何東西,而 return 一個新的 function 的 function 我們就稱作 HOF (Higher-Order Function),底下是範例:

1
2
3
4
5
6
7
8
9
var xHOF = function (x) {
return function (y) {
return x * y;
};
};
var xFive = xHOF(5);
var xTen = xHOF(10);
xFive(2); // 10
xTen(2); // 20

一個 HOC 就是一個函式 (function),接收到元件後,產生出另一個新的元件,在卡通影片中,可以想像成金剛戰士透過手表進行變身,或是數碼寶貝透過共振主人的無限可能進化成更強的模樣。一個 HOC 有底下四個特點:

  • Pure component: 沒有修改原來行為只有加強功能
  • Code reuse: 讓邏輯能夠重複使用
  • Render hijacking: 在真的元件 render 前,處理 render 前需要處理的事情,像是資料防呆或是將操作記錄發到後台
  • Manipulation: State 和 Props 統一控制,元件載入狀態動畫
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function HOC(WrappedComponent) {
return class Test extends Component {
render() {
const newProps = {
title: "New Header",
footer: false,
showFeatureX: false,
showFeatureY: true,
};

return <WrappedComponent {...this.props} {...newProps} />;
}
};
}

有 staticMethod 的話要自己複製:

1
2
3
4
5
6
7
function enhance(WrappedComponent) {
class Enhance extends React.Component {
/*...*/
}
Enhance.staticMethod = WrappedComponent.staticMethod;
return Enhance;
}

React 中的 Portals 是做什麼用的?

正常 react 所有的渲染都只掛載在某個 Parent 節點下,如果需要跳脫這個節點就需要 Portals,第一個參數可以放任何可被渲染的 child,第二個參數則是真實的 DOM element。

ReactDOM.createPortal(child, container)

React v16 錯誤邊界 (Error Boundaries) 是什麼?

錯誤邊界其實也只是個元件,錯誤邊界的概念像是一道防火門,讓當渲染發生錯誤時,能夠被關在 child component 中並顯示客製化的錯誤 UI,透過 componentDidCatch(error, info)static getDerivedStateFromError() 這兩個新增的周期來協助記錄相關錯誤。

This lifecycle method is invoked after an error has been thrown by a descendant component. It receives the error that was thrown as a parameter and should return a value to update state.

The signature of the lifecycle method is as follows,

static getDerivedStateFromError(error)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

componentDidCatch(error, info) {
// You can also log the error to an error reporting service
logErrorToMyService(error, info);
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>{"Something went wrong."}</h1>;
}
return this.props.children;
}
}

當撰寫完成後,使用上也非常簡單,只要把原來的元件包起來就好了,底下是範例

1
2
3
<ErrorBoundary>
<MyBugComponent />
</ErrorBoundary>

錯誤邊界在底下四種情形不會 catch 到錯誤

  • 在 Event handlers 中,只能夠自己寫 try catch
  • setTimeout 或 requestAnimationFrame 的 callbacks
  • 伺服器渲染的過程
  • ErrorBoundary 沒寫好自己發生的錯誤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { error: null };
this.handleClick = this.handleClick.bind(this);
}

// 在 Event handlers 中,只能夠自己寫 try catch
handleClick() {
try {
// Do something that could throw
} catch (error) {
this.setState({ error });
}
}

render() {
if (this.state.error) {
return <h1>Caught an error.</h1>;
}
return <button onClick={this.handleClick}>Click Me</button>;
}
}

React 中要怎麼實作 Props 相關檢查?

雖然 JavaScript 是弱型別的語言,但 React 內建 PropTypes check 機制,當 APP 處在開發模式下,React 會自動確認是否每個 props 都是如所設定的格式,若不正確 React 就會在命令列中產生警告的訊息,這個機制由於效能考量在 Production 環境中會被停用。

React 定義了底下十種型別:

  1. PropTypes.number
  2. PropTypes.string
  3. PropTypes.array
  4. PropTypes.object
  5. PropTypes.func
  6. PropTypes.node
  7. PropTypes.element
  8. PropTypes.bool
  9. PropTypes.symbol
  10. PropTypes.any

Props 中可分為必填和非必填,必填的後面則加上 isRequired 像是 PropTypes.number.isRequired,如果陣列中的物件需要定義則可以搭配使用 React.PropTypes.shape()React.PropTypes.arrayOf(),如果 Props 會是變動的,也可以使用 React.PropTypes.oneOfType()

1
2
3
4
5
6
7
8
9
10
11
12
ReactComponent.propTypes = {
arrayWithShape: React.PropTypes.arrayOf(
React.PropTypes.shape({
name: React.PropTypes.string.isRequired,
weight: React.PropTypes.number.isRequired,
})
).isRequired,
};

ReactComponent.PropTypes = {
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};

如何在頁面載入時自動 focus 在輸入框上?

只需要幫 input 加上參照 ref 就可以在 componentDidMount() 後針對 input 進行操作。不過這種 inline function 的寫法在元件更新的時候因為底層的邏輯會被執行兩次,所以不被推薦。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class App extends React.Component {
componentDidMount() {
this.nameInput.focus();
}

render() {
return (
<div>
<input defaultValue={"Won't focus"} />
<input
ref={(input) => (this.nameInput = input)}
defaultValue={"Will focus"}
/>
</div>
);
}
}

ReactDOM.render(<App />, document.getElementById("app"));

比較推薦的寫法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class UserForm extends Component {
handleSubmit = () => {
console.log("Input Value is: ", this.input.value);
};

setSearchInput = (input) => {
this.input = input;
};

render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" ref={this.setSearchInput} /> // Access DOM input in
handle submit
<button type="submit">Submit</button>
</form>
);
}
}

FAQ:React 面試與核心觀念常見問題

Q1:Virtual DOM 真的能讓網頁變快嗎?有沒有什麼誤區?

A:Virtual DOM 原理 的核心價值不在於「比原生操作快」,而在於「提供足夠好的效能同時極大化開發效率」。在極其簡單的 DOM 操作中,原生 JS 會更快。但在複雜的單頁應用中,React 透過 Reconciliation 演算法避免了昂貴的整頁重繪。常見的誤區是認為只要用 React 效能就一定好,實際上若不注意不必要的重新渲染(如未妥善使用 React.memo),效能依然會大幅下降。

Q2:Hooks 出現後,還有必要在大型專案中使用 Redux 嗎?

A:這取決於狀態的複雜度。對於「全域共享且頻繁變動」的資料,Redux 與狀態管理面試 依然強調其單向資料流與中間件(Middleware)帶來的可預測性。對於中小型專案,使用 React 內建的 Context API 搭配 useReducer 通常已足夠。在高標準的 React JS 觀念解析 中,應根據狀態的「穿透深度」與「追蹤需求」來決定工具選型。

Q3:如何向面試官解釋 Reconciliation (調和) 的運作流程?

A:您可以將 Reconciliation 解釋為 React 的「Diffing 過程」。當狀態改變時,React 會生成一棵新的 Virtual DOM 樹,並與舊樹對比。它採用了兩項高品質的假設:1. 相同類型的元件會產生相似的結構;2. 透過 key 屬性,React 可以識別穩定存在的節點。這讓複雜度從 O(n³) 降低到 O(n),實現了高效的 React 生命週期管理 與畫面更新。


同場加映

在面試的整個流程中,其實有許多事情是可以多加強的,底下也列出幾篇文章,分享這幾年面試下來的心得給大家:


喜歡這篇文章,請幫忙拍拍手喔 🤣