你真的瞭解React嗎?這裏有50個React面試問題
原創: 少帥blog
如果你是一位有理想的前端開發人員,並且正在準備面試,那麼這篇文章就是爲你準備的。本文收集了 React 面試中最常見的 50 大問題,這是一份理想的指南,讓你爲 React 相關的面試做好充分的準備工作。
首先我們快速瞭解一下 React 在市場上的需求和現狀,然後再開始討論 React 面試問題。
JavaScript 工具的市場地位正在緩慢而穩定地上升當中,而對 React 認證的需求正在飛速增長。選擇正確的技術來開發應用程序或網站變得愈加艱難。React 被認爲是 JavaScript 語言中增長最快的框架。
虛擬 DOM 和可複用部件等獨特特性吸引了前端開發人員的注意。儘管成熟的框架(如 Angular、Meteor 和 Vue 等)在 MVC(模型 - 視圖 - 控制器)中只是一個“視圖”庫,但它們都有很強的競爭力。下圖顯示了常見 JS 框架的趨勢:
以下是面試官最有可能提出的 50 個面試問題和答案:
- React 是 2011 年由 Facebook 開發的前端 JavaScript 庫。
- 它遵循基於組件的方法,這種方法可以用來構建可複用的 UI 組件。
- 它用於複雜的交互式 Web 端和移動端用戶界面開發。
- 儘管它在 2015 年纔開源,但得到了一家巨頭的支持
- 輕量級 DOM,以獲得更好的性能。
- 在 React 中,一切都被視爲組件
- React 使用 JSX(JavaScript eXtension),使我們可以編寫類似於 HTML 的 JavaScript。
- React 不是直接運行在瀏覽器的文檔對象模型(DOM)上,而是運行在虛擬 DOM 上。
- ReactJS 遵循單向數據流或單向數據綁定。
- 可以提高應用程序的性能。
- 可以方便地用在客戶端和服務端。
- 由於有了 JSX,代碼的可讀性提高了。
- 使用 React 後,編寫 UI 測試用例變得非常容易。
- React 只是一個庫,而不是一個成熟的框架。
- 它的庫很大,需要花費一些時間來理解。
- 新手程序員可能很難入門。
- 由於它使用了內聯模板和 JSX,編碼也比較複雜。
JSX 是 JavaScript XML 的簡寫。這是 React 使用的一種文件類型,具備 JavaScript 的表現力,並使用 HTML 作爲模板語法。這樣一來 HTML 文件理解起來就非常簡單。這種文件可以創造穩健的應用程序並提高其效率。下面是一個 JSX 實例:
render(){
return(
<div>
<h1> Hello World from Codersera!!</h1>
</div>
![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20191129093506630.jpg) );
}
虛擬 DOM 是輕量級的 JavaScript 對象,一開始只是真實 DOM 的一個副本。它是一個節點樹,將組件列爲對象及其屬性和內容的列表。React 的渲染功能從 React 的各個部分生成一個節點樹。然後,它會根據由不同用戶或系統行爲引起的信息模型突變來更新此樹。
虛擬 DOM 的工作機制只有簡單的三步組成。
1.每當任何基礎信息更改時,整個 UI 就會以虛擬 DOM 的表示形式重新渲染。
2.然後計算先前的 DOM 表示和新的 DOM 表示之間的區別。
3. 計算完成後,只有實際更改的內容纔會更新到真實 DOM。
React 使用 JSX(JavaScript eXtension),我們可以用它編寫類似於 HTML 的 JavaScript。但由於 JSX 不是合法的 JavaScript,因此瀏覽器無法直接讀取它。如果 JavaScript 文件包含 JSX,則必須將其轉換。你需要一個轉換器將 JSX 轉換爲瀏覽器可以理解的常規 Javascript。目前最常用的轉換器是 Babel。
ES5 和 ES6 的語法區別如下:
// ES5
var React = require('react');
// ES6
import React from 'react';
******** export vs exports *********
// ES5
module.exports = Component;
// ES6
export default Component;
****** function *****
// ES5
var MyComponent = React.createClass({
render: function() {
return <h3> Hello CoderSera! </h3>
},
});
// ES6
class MyComponent extends React.Component {
render() {
return <h3> Hello CoderSera! </h3>
}
}
******* props ******
// ES5
var App = React.createClass({
propTypes: { name: React.PropTypes.string },
render: function() {
return <h3> Hello, { this.props.name }! < /h3>
},
});
// ES6
class App extends React.Component {
render() {
return <h3> Hello, { this.props.name }! </h3>
}
}
****** state *****
// ES5
var App = React.createClass({
getInitialState: function() {
return { name: 'world' };
}
render: function() {
return <h3> Hello, { this.state.name }! < /h3>;
},
});
// ES6
class App extends React.Component {
constructor() {
super();
this.state = { name: 'world' };
}
render() {
return <h3> Hello, { this.state.name }! < /h3>
}
render() {
return;
<h3> Hello, { this.state.name }! < /h3>
}
React 應用程序的 UI 構建塊都是組件。這些部分將整個 UI 劃分爲許多可自治和可複用的微小部分。然後獨立的某個部分發生變化就不會影響 UI 的其餘部分。
它被視爲普通函數,但 render() 函數必須返回某些值,無論值是否爲空。調用組件文件時默認會調用 render() 方法,因爲組件需要顯示 HTML 標記,或者我們可以說 JSX 語法。每個 React 組件必須有一個 render() 函數,它返回單個 React 元素,該元素代表原生 DOM 組件。如果需要渲染多個 HTML 元素,則必須將它們分組在一個封閉的標籤內,如 < form >、< group >和 < div > 等。此函數必須保持純淨,就是說它在每次調用時必須返回相同的結果。
import React, { Component } from 'react';
class App extends Component {
render() {
return (<div> <h1 className='App-title'> hello CoderSera </h1></div>)
}
}
export default App;
Hooks 是一項新功能,使你無需編寫類即可使用狀態等 React 功能。來看一個 useState hook 示例:
<em>import </em>{useState} <em>from </em>'react';<br><br><em>function </em>Example() {<br> <em>// Declare a new
- Props 用於將數據從父級傳遞到子級或由組件本身傳遞。它們是不可變的,因此不會更改。
- Props 是不可變的。因爲它們是基於純函數的概念開發的。在純函數中,我們無法更改參數數據。因此在 ReactJS 中也無法更改 props 的數據。
組件可以通過狀態來跟蹤其執行的任何渲染之間的信息。
狀態用於可變數據或將要更改的數據。這對於用戶輸入尤其方便。以搜索欄爲例,用戶輸入數據時他們看到的內容也會更新。
可以使用 this.setState() 更新組件的狀態。
class MyComponent extends React.Component {
constructor() {
super();
this.state = {
name: 'Maxx',
id: '101'
}
}
render()
{
setTimeout(()=>{this.setState({name:'Jaeha', id:'222'})},2000)
return (
<div>
<h1>Hello {this.state.name}</h1>
<h2>Your Id is {this.state.id}</h2>
</div>
);
}
}
ReactDOM.render(
<MyComponent/>, document.getElementById('content')
);
粗箭頭=>用於定義匿名函數,這通常是將參數傳遞給回調函數的最簡單方法。但是你需要在使用它時優化性能。注意:每次渲染組件時,在 render 方法中使用箭頭函數都會創建一個新函數,這可能會影響性能。
//General way
render() {
return(
<MyInput onChange={this.handleChange.bind(this) } />
);
}
//With Arrow Function
render() {
return(
<MyInput onChange={ (e) => this.handleOnChange(e) } />
);
}
React 組件的生命週期分爲三個不同階段:
初始化:在初始化階段,我們爲 this.props 和 this.state 定義默認值和初始值。
掛載:掛載是將組件插入 DOM 時發生的過程。
更新:這個階段中,每當狀態更改或組件收到新的 prop 時,組件都會更新。
卸載:這是從 DOM 卸載組件的階段。
一些最重要的生命週期方法包括:
componentWillMount()——在初始渲染髮生之前,即在 React 將組件插入 DOM 之前立即調用一次。請務必注意,在此方法中調用 this.setState() 不會觸發重新渲染。
componentDidMount()——在渲染函數之後觸發此方法。現在可以訪問更新的 DOM,這意味着該方法是初始化其他需要訪問 DOM 的 Javascript 庫以及數據提取操作的最佳選擇。
componentWillReceiveProps()——componentWillReceiveProps() 在組件接收新 props 時調用。在調用 render() 方法之前,我們可以用這個方法對 prop 過渡做出反應。在此函數中調用 this.setState() 不會觸發額外的重新渲染,我們可以通過 this.props 訪問舊的 props。
shouldComponentUpdate()——我們可以用它來決定下一個組件的狀態是否應觸發重新渲染。此方法返回一個布爾值,默認爲 true。但是我們可以返回 false,並且不會調用以下方法:
componentWillUpdate()——當接收到新的 props 或狀態時,在渲染(更新)之前立即調用此方法。我們可以用它在更新之前做準備,但是不允許使用 this.setState()。
componentDidUpdate()——React 更新 DOM 後立即調用此方法。我們可以使用此方法與更新後的 DOM 交互,或執行任何渲染後操作。
componentWillUnmount()——從 DOM 卸載組件之前立即調用此方法。我們可以用它執行可能需要的任何清理工作。
在 React 中,事件是對特定動作(如鼠標懸停、鼠標單擊和按鍵等)觸發的反應。處理這些事件類似於處理 DOM 元素上的事件。但是在語法上存在一些差異,例如:
- 事件命名使用駝峯式大小寫,而不是僅使用小寫字母。
- 事件作爲函數而不是字符串傳遞。
事件參數包含一組特定於事件的屬性。每個事件類型都包含它自己的屬性和行爲,這些屬性和行爲只能通過它的事件處理程序訪問。
class Display extends React.Component({
show(evt) {
// code
},
render() {
// Render the div with an onClick prop (value is a function)
return (
<div onClick={this.show}>Click Me!</div>
);
}
});
合成事件是圍繞瀏覽器原生事件充當跨瀏覽器包裝器的對象。它們將不同的瀏覽器行爲合併爲一個 API。這樣做是爲了確保在各個瀏覽器的事件中顯示一致的特徵。
Ref 是 React 引用的簡寫。它是一個屬性,幫助存儲對特定元素或組件的引用,由組件渲染的配置函數返回。它用於返回對渲染返回的特定元素或組件的引用。當我們需要 DOM 測量或向組件添加方法時,它們會派上用場。
class ReferenceDemo extends React.Component{
display() {
const name = this.inputDemo.value;
document.getElementById('disp').innerHTML = name;
}
render() {
return(
<div>
Name: <input type="text" ref={input => this.inputDemo = input} />
<button name="Click" onClick={this.display}>Click</button>
<h2>Hello <span id="disp"></span> !!!</h2>
</div>
);
}
}
以下是應使用 ref 的情況:
當你需要管理焦點、選擇文本或媒體播放時。
觸發命令式動畫。
與第三方 DOM 庫集成。
可以使用 export 和 import 屬性來模塊化軟件。它們有助於在不同的文檔中單獨編寫組件。
//ChildComponent.jsx
export default class ChildComponent extends React.Component {
render() {
return( <div>
<h1>This is a child component</h1>
</div>)
}
}
//ParentComponent.jsx
import ChildComponent from './childcomponent.js';
class ParentComponent extends React.Component {
render() {
return(
<div>
<App />
</div>
);
}
}
React 提供了一種有狀態的,響應式的方法來構建表單。與其他 DOM 元素不同,HTML 表單元素在 React 中的工作機制有所不同。例如,表單數據通常由組件而不是 DOM 處理,並且通常使用受控組件來實現。
區別在於可以使用回調函數來處理表單事件,然後使用容器的狀態存儲表單數據。這使你的組件可以更好地控制表單控制元素和表單數據。
回調函數是在發生事件(包括更改表單控制值或表單提交)時觸發的。
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleSubmit} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
React 中的高階組件是一種在組件之間共享通用功能而無需重複代碼的模式。
高階組件實際上不是組件,它是一個接受組件並返回新組件的函數。它將一個組件轉換爲另一個組件,並添加其他數據或功能
代碼複用,邏輯和引導抽象。
渲染劫持。
狀態抽象和控制。
Props 操控。
React 並沒有在我們的組件中編寫 shouldCom- ponent 方法,而是引入了一個帶有內置 shouldComponentUpdate 實現的新組件,它是 React.PureComponent 組件。
React.PureComponent 通過淺層 prop 和狀態比較來實現它。在某些情況下,你可以使用 React.PureComponent 來提高性能。
鍵可幫助 React 識別哪些項目已更改、添加或刪除。應該爲數組內的元素提供鍵,以賦予元素穩定的身份。鍵必須是唯一的。
當使用動態創建的組件或用戶更改列表時,React 鍵非常有用。設置鍵值後,更改後的組件就能保持唯一標識。
MVC 不能解決代碼複雜性問題。它也不能解決代碼複用或靈活性問題。
它不保證解耦代碼。
Flux 是 Facebook 內部與 React 搭配使用的架構。它不是框架或庫。只是一種新型的體系結構,是對 React 和單向數據流概念的補充:
Flux 的各個組成部分如下:
- 動作(Actions)——幫助數據傳遞到調度器的輔助方法。
- 調度器(Dispatcher)——接收動作並將負載廣播到已註冊的回調。
- 存儲(Stores)——具有已註冊到調度器的回調的應用程序狀態和邏輯的容器。
- 控制器視圖(ControllerViews)——從組件中獲取狀態並通過 props 傳遞給子組件的 React 組件。
Redux 是一種狀態管理工具。儘管它主要與 React 搭配使用,但也可以與其他任何 JavaScript 框架或庫搭配。
Redux 允許你在一個稱爲存儲(Store)的對象中管理整個應用程序狀態。
對存儲的更新將觸發與存儲的已更新部分連接的組件的重新渲染。當我們想要更新某些東西時,我們稱之爲動作(Action)。我們還創建函數來處理這些動作並返回更新的存儲。這些函數稱爲 Reducer。
單一可信來源:整個應用程序的狀態存儲在單個存儲區中的對象 / 狀態樹中。單一狀態樹使我們能更容易地跟蹤歷史更改,更方便地調試或檢查應用程序。
狀態是隻讀的:更改狀態的唯一方法是觸發動作。動作是描述更改的普通 JS 對象。就像狀態是數據的最小表示一樣,動作是數據更改的最小表示。
使用純函數更改:爲了確認動作是如何轉換狀態樹的,你需要純函數。純函數是返回值僅取決於其參數值的函數。
單一可信源(SSOT)是構造信息模型和相關數據模式的實踐,其中每個數據元素都只能在一個地方掌握(或編輯)
Redux 使用“存儲”將應用程序的整個狀態存儲在一個位置。因此,組件的所有狀態都存儲在存儲中,並且存儲本身會接收更新。單一狀態樹使我們能更容易地跟蹤歷史更改,更方便地調試或檢查應用程序。
- 動作——這是一個描述發生了什麼的對象。
- Reducer——確定狀態如何變化的地方。
- 存儲——整個應用程序的狀態 / 對象樹保存在存儲中。
- 視圖——僅顯示存儲提供的數據。
React 中的動作必須具有 type 屬性,該屬性指示正在執行的 ACTION 的類型。必須將它們定義爲字符串常量,你也可以爲其添加更多屬性。在 Redux 中使用稱爲“動作創建者”的函數來創建動作。以下是動作和動作創建者的示例:
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
Reducer 是用於指示 ACTION 反應中應用程序狀態變化的簡單功能。它接收先前的狀態和動作,然後返回新的狀態。它根據動作類型確定需要哪種更新,然後返回新值。如果沒有要完成的工作,它將按原樣返回先前狀態。
存儲是一個 JavaScript 對象,可以保存應用程序的狀態,並提供一些輔助方法來訪問狀態、調度動作並記錄偵聽器。應用程序的整個狀態 / 對象樹存儲在單個存儲中。因此 Redux 非常容易理解且可預測。我們可以將中間件轉移到存儲,以管理數據處理任務,並維護更改存儲狀態的各種活動的日誌。通過 Reducer,所有活動都返回新的狀態。
Redux 的優點如下:
- 結果的可預測性——由於總是有單一可信源,比如存儲,因此當前狀態與動作及應用程序的其他部分同步時不會出現混亂。
- 可維護性——代碼易於維護,具有可預測的結果和嚴格的結構。
- 服務端渲染——你只需將在服務器上創建的存儲傳遞給客戶端即可。這對於初始渲染非常有用,並優化了應用程序性能,提供了更好的用戶體驗。
- 開發人員工具——從動作到狀態更改,開發人員可以利用這些工具實時跟蹤應用程序中發生的所有事情。
- 社區和生態系統——Redux背後擁有巨大的社區,用起來更加便利。大批優秀的開發者爲庫的發展做出了貢獻,並開發了很多應用程序。
- 易於測試——Redux
的代碼主要是較小的、純淨的和孤立的函數。這使代碼可測試且獨立。 組織——Redux
精確地規定了代碼的組織方式,這使得團隊合作時代碼更加一致,更容易理解。
React Router 是建立在 React 之上的功能強大的路由庫。它使 URL 與網頁上顯示的數據保持同步。它保持標準化的結構和行爲,可用於開發單頁 Web 應用程序。React Router 有一個簡單的 API。React Router 提供了一種方法,只會顯示你的應用中路由匹配你的定義的那些組件。
在 Switch 組件內,Route 和 Redirect 組件嵌套在內部。從 Switch 頂部的 Route/Redirect 組件開始到底部的 Route/Redirect,根據瀏覽器中當前的 URL 是否與 Route/Redirect 組件的 prop/ 路徑匹配,將每個組件評估爲 true 或 false。
Switch 只會渲染第一個匹配的子級。當我們嵌套了下面這樣的路由時真的很方便:
<Switch>
<Route path="/accounts/new" component={AddForm} />
<Route path={`/accounts/:accountId`} component={Profile} />
</Switch>
路由器用於定義多個路由,並且當用戶鍵入特定的 URL 時,如果該 URL 與路由器內部定義的任何“路由”的路徑匹配,則該用戶將被重定向到該路由。因此我們需要在應用程序中添加一個路由器庫,以允許創建多個路由,每個路由都爲我們指向一個獨特的視圖。
從 React Router 包導入的組件有兩個屬性,一個是將用戶引導到指定路徑的 path,另一個是用於定義所述路徑中內容的 component。
<switch>
<route exact path=’/’ component={Home}/>
<route path=’/posts/:id’ component={Newpost}/>
<route path=’/posts’ component={Post}/>
</switch>
就像 React 基於組件的理念一樣,在 React Router v4 中 API 是“完全組件化的”。路由器可以可視化爲單個根組件(),其中包含特定的子路由()。
無需手動設置歷史值:在 React Router v4 中,我們要做的就是將路由包裝在組件中。
包是拆分的:三個包分別用於 Web、Native 和 Core。這使我們的應用更加緊湊。它們的編碼樣式類似,所以很容易來回切換。