1. 程式人生 > 實用技巧 >React中常被問到的面試題

React中常被問到的面試題

什麼是jsX

要了解jsX,首先先了解什麼三個主要問題,什麼事 VDOM,差異更新和 JSX 建模:

VDOM,也叫虛擬 DOM,它是僅存於記憶體中的 DOM,因為還未展示到頁面中,所以稱為 VDOM

varvdom =document.createElement("div");

上面這一句就是最簡單的虛擬 DOM

var vdom = document.createElement("div");
document.body.append(vdom);

上面這兩句就是把虛擬 DOM 轉化為 真實 DOM,其實就是把節點 append 到頁面中

常見 DOM 操作,就三類:增、刪、改。對應的 DOM 操作如下:

DOM 操作DOM 方法
增加一個節點 appendChild
刪除一個節點 removeChild
更改一個節點 replaceChild

以前我們寫程式碼經常會拼接完模板,簡單粗暴的用$(el).html(template)整塊節點替換

這樣做最大的問題在於效能,如果頁面比較小,問題不大,但如果頁面龐大,這樣會出現卡頓,使用者體驗會很差,所以解決辦法就是差量更新

差量更新就是隻對局面的html片段進行更新。比如你加了一個節點,那麼我就只更新這個節點,我無需整個模板替換。這樣做效率就會提高。但問題在於,不知道哪個節點更新了,哪個節點刪除了,哪個節點替換了,所以我們需要對 DOM 建模

DOM 建模,簡單點說就是用一個 JS 物件來表示 VDOM。

如果我們可以用一個 JS 物件來表示 VDOM,那麼這個物件上多一個屬性(增加節點),少一個屬性(刪除節點),或者屬性值變了(更改節點),就很清醒了

DOM 也叫 DOM 樹,是一個樹形結構,DOM 樹上有很多元素節點,要對 VDOM 進行建模,本質上就是對一個個元素節點進行建模,然後再把節點放回 DOM 樹的指定位置

JSX 建模,每個節點都是由以下三部分組成:

  • type : 元素型別
  • props : 元素屬性
  • children : 子元素集合
{type:"div",props: null, children:[
       {type:"img",props:{"src":"avatar.png", "className":"profile"},children:[],
       {type:"h3",props: null, children:[{[user.firstName, user.lastName].join(' ')}],
]}

上面 VDOM 建模是用下面的 HTML 結構轉出來的

var profile = (
  <div>
    <img src="avatar.png" className="profile" />
    <h3>{[user.firstName, user.lastName].join(" ")}</h3>
  </div>
);

但這段程式碼並不是合法的 js 程式碼,它是一種被稱為 jsx 的語法擴充套件,通過它我們就可以很方便的在 js 程式碼中書寫 html 片段

本質上,jsx 是語法糖,上面這段程式碼會被 babel 轉換成如下程式碼

react.createElement(
  "div",
  null,
  react.createElement("img", {
    src: "avatar.png",
    className: "profile"
  }),
  React.createElement("h3", null, [user.firstName, user.lastName].join(" "))
);

而上面的這段被轉化的程式碼是 將我們的 VDOM 配合React.createElement(一般應該是createElement函式)轉化為真實 DOM

注意,如果是自定義元件<App />會轉化為React.createElement(App, null),因為元件是class App extends React.Component {}這樣定義的,所以 App 進入createElement函式裡面就會變成是一個物件

這裡我們可以把這個函式放進createElement()裡面生成一個 VDOM 物件,然後用生成的 VDOM 物件,配合render()生成一個 DOM 插入頁面,從而轉變成真實 DOM 結構

元素和元件有什麼區別

React 元素,它是 React 中最小基本單位,我們可以使用上面提到的 JSX 語法輕鬆地建立一個 React 元素:

constelement =<div>It is element</div>;

這個元素經過 babel 轉化之後會變成帶React.createElement的函式,而React.createElement()構建 React 元素的時候。它接受三個引數,第一個引數可以是一個標籤名。如 div、p,或者 React 元件。第二個引數為傳入的屬性,如 class,style。第三個以及之後的引數,皆作為元件的子元件。

React.createElement(type, [props], [...children]);

React.createElement它執行後是一個普通的物件,由於 React 元素不是真實的 DOM 元素,所以也沒辦法直接呼叫 DOM 原生的 API。上面的 JSX 轉譯後的物件大概是這樣的:

{
  "_context": Object,
  "_owner": null,
  "key": null,
  "props": {
    "className": null,
    "children": "It is element"
  },
  "ref": null,
  "type": "div"
}

而 React 中有三種方法構建元件:

  • React.createClass() 舊版的方法現在不建議使用
  • ES6 類 推薦使用
  • 無狀態函式

React.createClass()由於是舊版本的,我們重點講兩種就夠了,一種是函式式(無狀態函式),一種是類式(ES6 類),就是用ES6 class我們所有的元件都繼承自React.Component
函式式很簡單,就像我們平常寫函式一個,接受一個引數作為輸入,然後進行相應的輸出,只不過它輸出的 JSX 格式,注意元件只能有一個根元素:

function Wscats(props) {
  return <h1> {props.name}</h1>;
}

//ES6
const Wscats = ({ props }) => (
  <div>
    <h1>{props.name}</h1>
  </div>
);

類式元件如下,是一個純函式:

import React from 'react';
//推薦這種
class Wscats extends React.Component {
  render() {
    return  <h1> {this.props.name}</h1>
  }
}
//or 這種方法將要廢棄
var Wscats = React.createClass({
  render() {
    return  <h1> {this.props.name}</h1>
  }
}

React.createClass()和ES6 class構建的元件的資料結構本質都是類,而無狀態元件資料結構是純函式,但它們在 React 被能視為元件,綜上所得元件是由元素構成的,元素是構造元件的重要部分,元素資料結構是普通物件,而元件資料結構是類或純函式。

類元件和函式元件的區別

類元件有生命週期和狀態,而函式元件則沒有。

React 給類元件定義了非常完善的生命週期函式,類元件渲染到頁面中叫掛載mounting,所以渲染完成後,叫做componentDidMount, 類元件的解除安裝叫Unmount,所以類元件將要解除安裝 叫做componentWillUnmount。我們想要在什麼時候使用狀態,就可以直接呼叫生命週期函式,把想要做的事情寫到函式裡面,生命週期函式直接寫在類元件內部,類元件在初始化時會觸發 5 個鉤子函式:

id鉤子函式用處
1 getDefaultProps() 設定預設的 props,也可以用 defaultProps 設定元件的預設屬性
2 getInitialState() 在使用 es6 的 class 語法時是沒有這個鉤子函式的,可以直接在 constructor 中定義 this.state。此時可以訪問 this.props
3 componentWillMount() 元件初始化時只調用,以後元件更新不呼叫,整個生命週期只調用一次,此時可以修改 state
4 render() react 最重要的步驟,建立虛擬 dom,進行 diff 演算法,更新 dom 樹都在此進行。此時就不能更改 state 了
5 componentDidMount() 元件渲染之後呼叫,可以通過 this.getDOMNode()獲取和操作 dom 節點,只調用一次

類元件在更新時也會觸發 5 個鉤子函式:

id鉤子函式用處
6 componentWillReceivePorps(nextProps) 元件初始化時不呼叫,元件接受新的 props 時呼叫
7 shouldComponentUpdate(nextProps, nextState) react 效能優化非常重要的一環。元件接受新的 state 或者 props 時呼叫,我們可以設定在此對比前後兩個 props 和 state 是否相同,如果相同則返回 false 阻止更新,因為相同的屬性狀態一定會生成相同的 dom 樹,這樣就不需要創造新的 dom 樹和舊的 dom 樹進行 diff 演算法對比,節省大量效能,尤其是在 dom 結構複雜的時候。不過呼叫 this.forceUpdate 會跳過此步驟
8 componentWillUpdate(nextProps, nextState) 元件初始化時不呼叫,只有在元件將要更新時才呼叫,此時可以修改 state
9 render() 同上
10 componentDidUpdate() 元件初始化時不呼叫,元件更新完成後呼叫,此時可以獲取 dom 節點。還有一個解除安裝鉤子函式
11 componentWillUnmount() 元件將要解除安裝時呼叫,一些事件監聽和定時器需要在此時清除

比如,頁面渲染完成後時間自動加一秒,這時還要涉及到類元件的狀態更改。React 不允許直接更改狀態, 或者說,我們不能給狀態(如: date)進行賦值操作, 必須呼叫元件的setState()方法去更改狀態。這裡寫一個函式changeTime來更改狀態,詳情看 setState 更改狀態

changeTime函式也可以直接寫到元件裡面,根據ES6 class語法的規定,直接寫在類中的函式都會繫結在原型上,所以this.changeTime可以呼叫。但要保證 this 指向的是我們這個元件,而不是其他的東西, 這也是在setInterval中使用箭頭函式的原因:

//類式元件
class Wscats extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: new Date()
    }; // 給元件新增狀態
  }
  changeTime() {
    this.setState({ date: new Date() });
  }
  // 生命週期函式
  componentDidMount() {
    setInterval(() => {
      this.changeTime();
    }, 1000);
  }
  render() {
    return (
      <div>
        <h1>{this.props.name}</h1>
        <h2>現在時間是:{this.state.date.toLocaleTimeString()}</h2>
      </div>
    );
  }
}
//元件的組合
function App() {
  return (
    <div>
      <Wscats name="Oaoafly" />
      <Wscats name="Eno" />
    </div>
  );
}

PureComponent 和 Component 的區別

PureCompoent是更具效能的Component的版本。它為你提供了一個具有淺比較的shouldComponentUpdate方法,也就是上面我們提到的那個類元件的生命週期,除此之外PureComponent和Component基本上完全相同。當狀態發生改變時,PureComponent將對 props 和 state 進行淺比較。另一方面,而Component是不會比較的,當shouldComponentUpdate被呼叫時,元件預設的會重新渲染,所以可以在Component裡面自己手動呼叫shouldComponentUpdate進行比較來獲取更優質的效能。

資源搜尋網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com

狀態和屬性的區別

props(properties 的縮寫)和 state 都是普通的 JS 物件。它們都是用來儲存資訊的,這些資訊可以控制組件的渲染輸出。

而它們的一個重要的不同點就是:

  • props 是傳遞給元件的(類似於函式的形參)
  • state 是在元件內被元件自己管理的(類似於在一個函式內宣告的變數)
class Test extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      message: "Hello World"
    };
  }

  render() {
    return (
      <div>
        <h1>{this.state.message} {this.props.message}</h1>
      </div>
    );
  }
}
// 傳遞Props給元件,message=”Hi“會被 Test元件裡面的 props接受
React.render(<Test message="Hi">, document.getElementById('#demo'))

所以,狀態(State)與屬性(Props)很類似,但 state 是元件私有的控制的,除了自身外部任何元件都無法訪問它,而 props 是元件從外部獲取的值,類似形參。