好程式設計師web前端培訓分享React學習筆記(一)

好程式設計師發表於2020-04-26

   好程式設計師 web前端培訓分享 React學習筆記(一) React的起源和發展 React  起源於 Facebook 的內部專案,因為該公司對市場上所有 JavaScript MVC 框架,都不滿意,就決定自己寫一套,用來架設Instagram 的網站。做出來以後,發現這套東西很好用,就在2013年5月開源了。

React與傳統MVC的關係

輕量級的檢視層 A JavaScript library for building user interfaces

React不是一個完整的MVC框架,最多可以認為是MVC中的V(View),甚至React並不非常認可MVC開發模式;React 構建頁面 UI 的庫。可以簡單地理解為,React 將將介面分成了各個獨立的小塊,每一個塊就是元件,這些元件之間可以組合、巢狀,就成了我們的頁面。

React高效能的體現:虛擬DOM

React高效能的原理:

Web開發中我們總需要將變化的資料實時反應到UI上,這時就需要對DOM進行操作。而複雜或頻繁的DOM操作通常是效能瓶頸產生的原因(如何進行高效能的複雜DOM操作通常是衡量一個前端開發人員技能的重要指標)。

React為此引入了虛擬DOM(Virtual DOM)的機制:在瀏覽器端用Javascript實現了一套DOM API。基於React進行開發時所有的DOM構造都是透過虛擬DOM進行,每當資料變化時,React都會重新構建整個DOM樹,然後React將當前整個DOM樹和上一次的DOM樹進行對比,得到DOM結構的區別,然後僅僅將需要變化的部分進行實際的瀏覽器DOM更新。而且React能夠批處理虛擬DOM的重新整理,在一個事件迴圈(Event Loop)內的兩次資料變化會被合併,例如你連續的先將節點內容從A-B,B-A,React會認為A變成B,然後又從B變成A UI不發生任何變化,而如果透過手動控制,這種邏輯通常是極其複雜的。

儘管每一次都需要構造完整的虛擬DOM樹,但是因為虛擬DOM是記憶體資料,效能是極高的,部而對實際DOM進行操作的僅僅是Diff分,因而能達到提高效能的目的。這樣,在保證效能的同時,開發者將不再需要關注某個資料的變化如何更新到一個或多個具體的DOM元素,而只需要關心在任意一個資料狀態下,整個介面是如何Render的。

React Fiber:

react 16之後釋出的一種react 核心演算法, React Fiber是對核心演算法的一次重新實現 (官網說法)。之前用的是diff演算法。

在之前React中,更新過程是同步的,這可能會導致效能問題。

React決定要載入或者更新元件樹時,會做很多事,比如呼叫各個元件的生命週期函式,計算和比對Virtual DOM,最後更新DOM樹,這整個過程是同步進行的,也就是說只要一個載入或者更新過程開始,中途不會中斷。因為JavaScript單執行緒的特點,如果元件樹很大的時候,每個同步任務耗時太長,就會出現卡頓。

React Fiber的方法其實很簡單——分片。把一個耗時長的任務分成很多小片,每一個小片的執行時間很短,雖然總時間依然很長,但是在每個小片執行完之後,都給其他任務一個執行的機會,這樣唯一的執行緒就不會被獨佔,其他任務依然有執行的機會。

React的特點和優勢

1、虛擬DOM

我們以前操作dom的方式是透過document.getElementById()的方式,這樣的過程實際上是先去讀取html的dom結構,將結構轉換成變數,再進行操作

reactjs定義了一套變數形式的dom模型,一切操作和換算直接在變數中,這樣減少了操作真實dom,效能真實相當的高,和主流MVC框架有本質的區別,並不和dom打交道

2、元件系統

react最核心的思想是將頁面中任何一個區域或者元素都可以看做一個元件 component

那麼什麼是元件呢?

元件指的就是同時包含了html、css、js、image元素的聚合體

使用react開發的核心就是將頁面拆分成若干個元件,並且react一個元件中同時耦合了css、js、image,這種模式整個顛覆了過去的傳統的方式

3、單向資料流

其實reactjs的核心內容就是資料繫結,所謂資料繫結指的是隻要將一些服務端的資料和前端頁面繫結好,開發者只關注實現業務就行了

4、JSX 語法

vue中,我們使用render函式來構建元件的dom結構效能較高,因為省去了查詢和編譯模板的過程,但是在render中利用createElement建立結構的時候程式碼可讀性較低,較為複雜,此時可以利用jsx語法來在render中建立dom,解決這個問題,但是前提是需要使用工具來編譯jsx

 

編寫第一個react應用程式

react開發需要引入多個依賴檔案:react.js、react-dom.js,分別又有開發版本和生產版本,create-react-app裡已經幫我們把這些東西都安裝好了。把透過CRA建立的工程目錄下的src目錄清空,然後在裡面重新建立一個index.js. 寫入以下程式碼:

// 從 react 的包當中引入了 React。只要你要寫 React.js 元件就必須引入React, 因為react裡有一種語法叫JSX,稍後會講到JSX,要寫JSX,就必須引入React import   React   from   'react' // ReactDOM 可以幫助我們把 React 元件渲染到頁面上去,沒有其它的作用了。它是從 react-dom 中引入的,而不是從 react 引入。 import   ReactDOM   from   'react-dom' // ReactDOM裡有一個render方法,功能就是把元件渲染並且構造 DOM 樹,然後插入到頁面上某個特定的元素上 ReactDOM.render( // 這裡就比較奇怪了,它並不是一個字串,看起來像是純 HTML 程式碼寫在 JavaScript 程式碼裡面。語法錯誤嗎?這並不是合法的 JavaScript 程式碼, “在 JavaScript 寫的標籤的”語法叫 JSX- JavaScript XML。    < h1 > 歡迎進入React的世界 < /h1>, // 渲染到哪裡    document .getElementById( 'root' ))

元素與元件

如果程式碼多了之後,不可能一直在render方法裡寫,所以就需要把裡面的程式碼提出來,定義一個變數,像這樣:

import   React   from   'react' import   ReactDOM   from   'react-dom' // 這裡感覺又不習慣了?這是在用JSX定義一下react元素 const   app   =   < h1 > 歡迎進入React的世界 < /h1> ReactDOM.render(

   app,

   document .getElementById( 'root' ))

函式式元件

由於元素沒有辦法傳遞引數,所以我們就需要把之前定義的變數改為一個方法,讓這個方法去return一個元素:

import   React   from   'react' import   ReactDOM   from   'react-dom' // 特別注意這裡的寫法,如果要在JSX裡寫js表示式(只能是表示式,不能流程控制),就需要加 {},包括註釋也是一樣,並且可以多層巢狀 const   app   =   (props)   =>   < h1 > 歡迎進入{props.name}的世界 < /h1> ReactDOM.render(

   app({

     name :   'react'

   }),

   document .getElementById( 'root' ))

這裡我們定義的方法實際上也是react定義元件的第一種方式-定義函式式元件,這也是無狀態元件。但是這種寫法不符合react的jsx的風格,更好的方式是使用以下方式進行改造

import   React   from   'react' import   ReactDOM   from   'react-dom' const   App   =   (props)   =>   < h1 > 歡迎進入{props.name}的世界 < /h1> ReactDOM.render(

   // React元件的呼叫方式    < App   name = "react"   /> ,

   document .getElementById( 'root' ))

這樣一個完整的函式式元件就定義好了。但要 注意!注意!注意! 元件名必須 大寫 ,否則報錯。

class元件

ES6的加入讓JavaScript直接支援使用class來定義一個類,react的第二種建立元件的方式就是使用的類的繼承, ES6 class 是目前官方推薦的使用方式,它使用了ES6標準語法來構建,看以下程式碼:

import   React   from   'react' import   ReactDOM   from   'react-dom' class   App   extends   React.Component   {

   render   ()   {

     return   (

       // 注意這裡得用this.props.name, 必須用this.props        < h1 > 歡迎進入{ this .props.name}的世界 < /h1>

     )

   }}ReactDOM.render(

   < App   name = "react"   /> ,

   document .getElementById( 'root' ))

執行結果和之前完全一樣,因為JS裡沒有真正的class,這個class只是一個語法糖, 但二者的執行機制底層執行機制不一樣。

·  函式式元件是直接呼叫, 在前面的程式碼裡已經有看到

·  es6 class 元件其實就是一個構造器,每次使用元件都相當於在例項化元件,像這樣:

import   React   from   'react' import   ReactDOM   from   'react-dom' class   App   extends   React.Component   {

  render   ()   {

  return   (

    < h1 > 歡迎進入{ this .props.name}的世界 < /h1>

   )

   }} const   app   =   new   App({

  name :   'react' }).render() ReactDOM.render(

  app,

  document .getElementById( 'root' ))

更老的一種方法

16以前的版本還支援這樣建立元件, 但現在的專案基本上不用

React.createClass({

   render   ()   {

     return   (

       < div > { this .props.xxx} < /div>

     )

   }})

元件的組合、巢狀

將一個元件渲染到某一個節點裡的時候,會將這個節點裡原有內容覆蓋

元件巢狀的方式就是將子元件寫入到父元件的模板中去,且react沒有Vue中的內容分發機制(slot),所以我們在一個元件的模板中只能看到父子關係

// 從 react 的包當中引入了 React 和 React.js 的元件父類 Component// 還引入了一個React.js裡的一種特殊的元件 Fragment import   React,   {   Component,   Fragment   }   from   'react' import   ReactDOM   from   'react-dom' class   Title   extends   Component   {

   render   ()   {

     return   (

       < h1 > 歡迎進入React的世界 < /h1>

     )

   }} class   Content   extends   Component   {

   render   ()   {

     return   (

       < p > React.js是一個構建UI的庫 < /p>

     )

   }} /** 由於每個React元件只能有一個根節點,所以要渲染多個元件的時候,需要在最外層包一個容器,如果使用div, 會生成多餘的一層domclass App extends Component {  render () {    return (        <div>            <Title />        <Content />      </div>    )  }}**/// 如果不想生成多餘的一層dom可以使用React提供的Fragment元件在最外層進行包裹 class   App   extends   Component   {

   render   ()   {

     return   (

       < Fragment >

         < Title   />

         < Content   />

       < /Fragment>

     )

   }}ReactDOM.render(

   < App /> ,

   document .getElementById( 'root' ))

#JSX 原理

要明白JSX的原理,需要先明白如何用 JavaScript 物件來表現一個 DOM 元素的結構?

看下面的DOM結構

< div   class = 'app'   id = 'appRoot' >

   < h1   class = 'title' > 歡迎進入React的世界 </ h1 >

   < p >

    React.js 是一個幫助你構建頁面 UI 的庫

   </ p ></ div >

上面這個 HTML 所有的資訊我們都可以用 JavaScript 物件來表示:

{

   tag :   'div' ,

   attrs :   {   className :   'app' ,   id :   'appRoot' },

   children :   [

     {

       tag :   'h1' ,

       attrs :   {   className :   'title'   },

       children :   [ '歡迎進入React的世界' ]

     },

     {

       tag :   'p' ,

       attrs :   null ,

       children :   [ 'React.js 是一個構建頁面 UI 的庫' ]

     }

   ]}

但是用 JavaScript 寫起來太長了,結構看起來又不清晰,用 HTML 的方式寫起來就方便很多了。

於是 React.js 就把 JavaScript 的語法擴充套件了一下,讓 JavaScript 語言能夠支援這種直接在 JavaScript 程式碼裡面編寫類似 HTML 標籤結構的語法,這樣寫起來就方便很多了。編譯的過程會把類似 HTML 的 JSX 結構轉換成 JavaScript 的物件結構。

下面程式碼:

import   React   from   'react' import   ReactDOM   from   'react-dom' class   App   extends   React.Component   {

   render   ()   {

     return   (

       < div   className = 'app'   id = 'appRoot' >

         < h1   className = 'title' > 歡迎進入React的世界 < /h1>

         < p >

           React.js   是一個構建頁面   UI   的庫

         < /p>

       < /div>

     )

   }} ReactDOM.render(

     < App   /> ,

   document .getElementById( 'root' ))

編譯之後將得到這樣的程式碼:

import   React   from   'react' import   ReactDOM   from   'react-dom' class   App   extends   React.Component   {

   render   ()   {

     return   (

       React.createElement(

         "div" ,

         {

           className :   'app' ,

           id :   'appRoot'

         },

         React.createElement(

           "h1" ,

           {   className :   'title'   },

           "歡迎進入React的世界"

         ),

         React.createElement(

           "p" ,

           null ,

           "React.js 是一個構建頁面 UI 的庫"

         )

       )

     )

   }} ReactDOM.render(

     React.createElement(App),

   document .getElementById( 'root' ))

React.createElement  會構建一個 JavaScript 物件來描述你 HTML 結構的資訊,包括標籤名、屬性、還有子元素等, 語法為

React.createElement(

   type,

   [props],

   [...children])

所謂的 JSX 其實就是 JavaScript 物件,所以使用 React 和 JSX 的時候一定要經過編譯的過程:

JSX —使用react構造元件,bable進行編譯—> JavaScript物件 —   ReactDOM.render() —>DOM元素 —>插入頁面

元件中DOM樣式

·  行內樣式

想給虛擬dom新增行內樣式,需要使用表示式傳入樣式物件的方式來實現:

// 注意這裡的兩個括號,第一個表示我們在要JSX裡插入JS了,第二個是物件的括號   < p   style = {{color : 'red' ,   fontSize : '14px' }} > Hello   world < /p>

行內樣式需要寫入一個樣式物件,而這個樣式物件的位置可以放在很多地方,例如 render 函式里、元件原型上、外鏈js檔案中

·  使用 class

React推薦我們使用行內樣式,因為React覺得每一個元件都是一個獨立的整體

其實我們大多數情況下還是大量的在為元素新增類名,但是需要注意的是, class 需要寫成 className (因為畢竟是在寫類js程式碼,會收到js規則的現在,而 class 是關鍵字)

< p   className = "hello"   style   =   { this .style} > Hello   world < /p>

·  不同的條件新增不同的樣式

有時候需要根據不同的條件新增不同的樣式,比如:完成狀態,完成是綠色,未完成是紅色。那麼這種情況下,我們推薦使用 classnames 這個包:

·  css-in-js

styled-components 是針對React寫的一套css-in-js框架,簡單來講就是在js中寫css。 npm連結

TodoList

元件化開發React todolist, 專案開發中的元件的基本目錄結構基本上是這樣的:

注意:一個元件只幹一件事情 ,所以TodoList和TodoItem要做成兩個元件,這樣也方便於後期理解shouldComponentUpdate


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913864/viewspace-2688472/,如需轉載,請註明出處,否則將追究法律責任。

相關文章