必定要熟記這些常被問到的React面試題

photo-1534447677768-be436bb09401.jpeg

什麼是 JSX

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

VDOM,也叫虛擬 DOM,它是僅存於內存中的 DOM,由於還未展現到頁面中,因此稱爲 VDOMreact

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

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

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

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

常見 DOM 操做,就三類:增、刪、改。對應的 DOM 操做以下:github

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

之前咱們寫代碼常常會拼接完模板,簡單粗暴的用$(el).html(template)整塊節點替換算法

這樣作最大的問題在於性能,若是頁面比較小,問題不大,但若是頁面龐大,這樣會出現卡頓,用戶體驗會不好,因此解決辦法就是差量更新json

差量更新就是隻對局面的 HTML 片斷進行更新。好比你加了一個節點,那麼我就只更新這個節點,我無需整個模板替換。這樣作效率就會提升。但問題在於,不知道哪一個節點更新了,哪一個節點刪除了,哪一個節點替換了,因此咱們須要對 DOM 建模數組

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

若是咱們能夠用一個 JS 對象來表示 VDOM,那麼這個對象上多一個屬性(增長節點),少一個屬性(刪除節點),或者屬性值變了(更改節點),就很清醒了性能優化

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

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 元素:

const element = <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方法,也就是上面咱們提到的那個類組件的生命週期,除此以外PureComponentComponent 基本上徹底相同。當狀態發生改變時,PureComponent 將對 props 和 state 進行淺比較。另外一方面,而Component是不會比較的,當 shouldComponentUpdate被調用時,組件默認的會從新渲染,因此能夠在Component裏面本身手動調用shouldComponentUpdate進行比較來獲取更優質的性能。

狀態和屬性的區別

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 是組件從外部獲取的值,相似形參。

若是文章和筆記能帶您一絲幫助或者啓發,請不要吝嗇你的贊和收藏,你的確定是我前進的最大動力😁

相關文章
相關標籤/搜索