天天看點

【react】react v16.13知識點總結(一)

一、react中的虛拟DOM

  • react中元件化是直接使用js實作,vue中通過

    .vue檔案

    實作;
  • 在vue中模闆

    template(模闆結構)->ast(普通對象)->render函數(帶變量的函數對象)->虛拟dom(指派的函數對象)

  • 在react中直接

    js->虛拟dom

  • 使用虛拟dom,頁面源碼中是沒有相應的dom标簽,頁面中元素都來自于引入的js檔案;浏覽器也不用解析相應html元素,直接解析js,形成真正的dom。
  • 與vue:react中挂載是嵌套在

    index.html的#app

    中;vue是直接替換;import引入時,都是将子元件檔案以對象鍵值對形式導入,不同的是react中jsx文法會被解析;但是生命周期都還是沒有開始;
  • vue是在父元件

    beforeMount周期後

    開始子元件的生命周期,通過解析子元件标簽觸發的元件生命周期;react也是,在解析到子元件标簽後才開始子元件的生命周期。
  • ** react中引入時子元件render函數中jsx文法已經被解析,但createElement()中值也是變量存在,因為生命周期還沒有開始;vue中引入子元件是隻是元件檔案的對象形式(不是元件對象),生命周期也沒有開始,加載時子元件render函數要在挂載階段與自身Vue執行個體結合才把render函數中變量指派,然後執行render函數,傳回h(具體值/),這個執行完就是虛拟dom;**
  • DOM
    • 本質

      :就是指用js對象表示的UI元素;是浏覽器在記憶體中形成的很複雜的對象;
    • 特點/差別

      :隻不過是浏覽器解析生成的,浏覽器在js中提供了固定的 DOM API來操作 DOM 對象;
    • 工作原理

      :當元素發生更新時,記憶體中存在新舊兩個DOM樹對象,浏覽器通過新樹替換舊樹進行重新渲染頁面;
  • 虛拟DOM
    • 本質

      :手動使用JS對象來模拟(相對真正dom對象做了簡化)DOM樹,也是對象,然後通過特定方法渲染成真正的DOM,在頁面中出效果;
    • 作用

      :彌補浏覽器不能新舊對比、實作指定更新的不足,為了實作DOM節點的高效更新;
    • 怎麼模拟DOM樹

      :通過JS建立對象,模拟一個DOM節點,節點中有children屬性描述子節點,通過節點間嵌套,就模拟出了一個DOM樹;
    • 特點/差別

      :不是由浏覽器提供的,是開發人員自己通過JS模拟出來的,浏覽器解析的是js代碼,然後參照這個js代碼建立真正dom樹展示;
    • 使用

      :在頁面更新前,使用JS文法模拟出新舊兩個DOM樹,(因為浏覽器沒有提供擷取它記憶體中DOM樹的接口),然後

      diff算法

      進行比較;讓浏覽器隻更新有變化的元素。
  • 像vue、react架構中,頁面都是通過虛拟DOM轉為真正DOM來展示的;原理都類似;隻是感覺react更直白一些,vue更貼心一些,寫的時候還是可以寫html、css;
  • react中建立頁面元素:與内部建立虛拟DOM做法類似,都是直接通過

    js+接口

    實作,不再直接寫html标簽;與vue不同(通過html标簽寫頁面);

二、react中的Diff算法

【react】react v16.13知識點總結(一)

前提

:有新舊兩個虛拟DOM了,通過把舊虛拟dom一步步修改變成新虛拟dom一樣的過程中,得到需要變化的元素;

意義

:diff 是通過JS層面的計算,對比新舊虛拟DOM,傳回一個patch對象,即更新檔對象,在通過特定的操作解析patch對象,完成頁面的重新渲染;

1、

tree diff

:将新舊兩個整體的虛拟DOM,逐層對比;其中包含元件對比、元素對比;

2、

componment diff

:(react中元件類似vue,就是首頁面引入的部分)在對比每一層時,進行元件之間對比;

  • 元件對比規則:
    • 相同位置,兩個元件類型相同,就暫且儲存先認為不用更新;如果類型都不同,那直接移除舊元件,建立元件替換到被移除的位置;(這些後會被記錄)

3、

element diff

:元件中元素之間的對比;

4、

key屬性

:把頁面中 DOM節點 與虛拟DOM中的對象,做一層關系。

三、react中的JSX文法

背景

:因為在react中書寫元素都是在js中,react原生提供了

react、react-dom

來支援;

import React from 'react'
/react子產品,用于專門來建立react元件、生命周期等;
import ReactDom from 'react-dom'
/react-dom子產品,用于将元件渲染到頁面上,内部封裝了和DOM相關的包;

var myDiv = React.createElement('div',{title:'mytitle',id:'myDiv'},'文本内容');
ReactDom.render(myDiv,document.getElementById('app'))
/=ReactDom.render(虛拟dom,嵌套元素)
           

不足

:原生方法書寫html元素,比較麻煩,開發人員更喜歡可以以手寫

html代碼

的方式定義頁面,是以react中提供了

JSX文法

來支援在 js 中書寫html标簽;

1、jsx介紹

  • 定義

    :符合 XML 規範的 JS 文法,即手寫的html标簽要符合XML标準;
  • 原理

    :内部将js中的html代碼用原生

    React.createElement方法

    轉換成

    js對象

    ,再交給

    ReactDOM.render()

    渲染;
  • 怎麼用

    :webpack一開始是不識别JSX文法的,需要安裝配置

    @babel/preset-react

    文法轉換工具(

    注:

    babel-loader 7.x對應:babel-preset-react);
  • 效果展示

var myDiv = <div id="myDiv">jsx識别的文法
  <p id="mySpan">js中寫html沒有文法提示</p>
  </div> 
// =後面就是jsx文法,
//會被解析成render函數的傳回值:
//React.createElement('div',{title:'mytitle',id:'myDiv'},'文本内容')

ReactDom.render(myDiv,document.getElementById('app')) //傳入render函數,内部執行形成得到createElement()函數,這個函數執行生成虛拟dom,并渲染出真正dom
           

2、jsx文法解析規則:

  • 基本規則

    :在

    js檔案中

    遇到

    <>

    就按html代碼解析,轉成js對象;遇到

    {}

    或者正常的js代碼就按js代碼解析;
  • 變化

    :在HTML代碼中有一些名稱與js關鍵字沖突,是以在使用時要改名;如:JSX中要寫

    <div className="myClass"></div>

    ,文法内會解析成正常

    <div class = "meClass">

  • JSX中html的注釋

    :單行、多行注釋
{/* 這是p标簽 */}
  <p id="mySpan">js中寫html沒有文法提示</p>
  {
    // 多行注釋
    // 多行注釋
  }
           

四、react中的元件

元件檔案

:元件檔案名字尾:

.jsx/.js

,差別在于

.jsx檔案

中有html文法提示;都需要然後在webpack中配置

babel文法轉換器

1、

function方式

定義元件

  • 函數元件通過

    props

    形參,接收外界傳進來的資料,将

    接收的資料以props對象的屬性方式存儲

    ,而且資料是隻讀的,不能内部修改;
  • 外界通過在函數标簽中定義屬性的方式傳遞資料;
  • 函數元件定義時必須大寫開頭,因為函數的元件使用方式就是以函數名為标簽名,而

    jsx文法

    中解析标簽是:小寫标簽按正常html标簽解析,大寫标簽才會當做元件标簽解析;
元件:Hello.js
import React from 'react'
function Person(props){
  return <div>
    <h1>哈哈---{props.name+"--"+props.age}</h1>
  </div>
}
export default Person
---
入口檔案:main.jsx
import Hello from './componments/Hello'  /=>類似vue,引入Hello元件直接就是render函數,
/=>這是由檔案内部導出時解析結果決定的
var one = {
  name:'zs',
  age:12
}
ReactDom.render(<Person one={one}></Person>
,document.getElementById('app'))
//或者可以展開方式:{props.name+"---"+props.age}
ReactDom.render(<Person {...one}></Person>
,document.getElementById('app'))
           

2、

class方式

定義元件

  • 類的執行個體是繼承構造函數中的屬性和方法;
  • 類中構造函數外定義的普通方法挂載到原型對象上,類的執行個體可以通過原型鍊使用;
  • 類中構造函數外定義的屬性(隻能定義靜态)、靜态方法是挂載到了構造器上,類的執行個體通路不到;
  • 補充

    :對比class與function構造函數
function Person(name,age){
  this.name = name;
  this.age = age;
}
Person.prototype.say = function(){
  console.log('函數原型上的方法');
}
Person.info = '構造函數自身的屬性';
Person.addInfo =function(){
  console.log('構造函數自身的方法');
};
var p1 = new Person('zs',21)
console.log(p1);
----
class Per{
  /類中隻能定義方法(執行個體方法、靜态方法)和靜态屬性
  /類中方法定義到構造函數原型上,隻能調用原型或通過執行個體使用
  /類中靜态屬性、靜态方法定義在構造函數自身,隻能自身或子類繼承後調用
  constructor(name,age){//類中的構造函數(方法),new執行個體自動執行
    this.name = name;
    this.age = age;
  }
  say(){//方法
    console.log('class中構造函數原型上的方法');
  }
  static info = '類中的靜态屬性';//靜态屬性
  static add = function(){
    console.log('靜态方法也定義構造函數自身');
  }
}
           
  • 補充

    :在class定義元件中主要用到

    類的封裝、繼承特性

class Per{
  constructor(name,age){
    this.name = name;
    this.age = age;
  }
  say(){
    console.log('定義在Per構造函數原型上的方法');
  }
  static info = 'zs';/構造函數中的屬性,隻能通過構造函數調用
}
class Chinese extends Per{
  constructor(name,age,color){
    super(name,age);/父類的傳參必須放在前面
    this.color = color;
  }
}
var p2 = new Chinese('yellow','zs',22)
console.log(Chinese.info);/子構造函數可以調用父構造函數中靜态屬性/方法,但是執行個體不行
           
  • 需要繼承

    React.component

  • 類中需要定義

    render方法傳回null或jsx文法(讓内部解析成createElement()函數)

  • 與函數元件類似,最終都是用名字做标簽名,内部最終傳回的都是:h();
  • ReactDom.render()

    ,參數1:使用的就是

    React.createElement()

main.js:
class Hello2 extends React.Component{ /=>繼承react元件功能
  render(){
    return <div>這是class類建立的元件{this.props.aa}</div>
  } /=>定義render函數,内部傳回值會被JSX解析,是以最終return的結果就是:createElement()函數;
}
ReactDom.render(<div>
  <Hello2 aa='asdClass'></Hello2> ://=這就相當于new了一個Hello2類的執行個體并執行了render函數,render是執行個體原型鍊上的方法
</div>,document.getElementById('app'))
           

3、對比兩種元件定義方式

  • 差別一:參數props的使用
    • 在function元件中,通過标簽接收參數,需要傳入

      props

      ,通過

      {props.[屬性名]}

      的方式使用;
    • 在class元件中,同樣标簽接收參數,不需要傳參數(也沒有地方接收),直接通過

      {this.props.[屬性名]}

      使用;
  • 差別二:兩者都不能對傳入參數做修改;
  • 差別三:函數元件是無狀态的元件;class類定義元件是有狀态的;
    • 有狀态:可以有自己的類似vue中data的屬性,即

      this.state={}

    • 函數元件使用時就是執行構造函數傳回 h()虛拟dom
    • class元件使用時也執行了new,同時也執行了render函數,狀态就可以在new時建立,在render函數執行時改變;
  • 有無狀态差別:
    • 有狀态元件:有私有資料(state屬性),有生命周期函數;适用于需要修改資料的元件;
    • 無狀态元件:沒有私有資料,無state屬性,無生命周期函數;适用于資料不改變的元件,

      如子元件

4、元件中state/data與props差別

  • 前者是元件私有的資料,通過ajax請求來的;
  • 後者是外界傳過來的資料;
  • 前者的資料是可讀可寫的;
  • 後者的資料是隻讀的;

五、react中的class有狀态元件應用

1、路徑問題

path.join(__dirname,'./aa'); /='aa' '/aa' './aa' 效果一樣:e:\QD\react\aa
path.join(__dirname,'../aa'); /= 向上一級:e:\QD\aa
不識别'/'根目錄

path.resolve(__dirname,'./aa'); /='aa' './aa' 效果一樣:e:\QD\react\aa
path.resolve(__dirname,'../aa'); /= 向上一級:e:\QD\aa
path.resolve(__dirname,'/aa'); /= e:\aa
都是轉為絕對路徑;resolve識别/,為根目錄
           

下一個》》2、

繼續閱讀