react 筆記

  1. react 基本概念解析
  2. react 的組件聲明周期
  3. react 高階組件,context, redux 等高級進(jìn)階

特別提醒:

  1. 新版本更新
    React.createClass({ ..... }) 為es5 的寫法,新版已經(jīng)被廢棄
    class { ..... } 為 es6 的寫法,推薦使用

  2. create-react-app 工程為自動創(chuàng)建新 react 工程的工具項(xiàng)目,該工具包含了打包、 測試、sourceMap、等功能。

  3. react 使用全家桶( react 項(xiàng)目中不可或缺的工具 )
    React 在開發(fā)/生產(chǎn) 階段需要一大堆的工具庫輔助開發(fā)
    編譯:babel
    狀態(tài)管理工具:redux
    單頁應(yīng)用:react-route

  4. dangerouslySetInnerHTML 用于設(shè)置不受保護(hù)的HTML
    <div dangerouslySetInnerHTML = {{ __html: this.state.不受保護(hù)的代碼片段 }}></div>

  5. 好的 React 命名習(xí)慣

    • 自定義的組件使用 首字母大寫的駝峰命名 (eg: InputComponent..... )
    • 自定義的屬性使用 小駝峰命名 ( eg: this.state.getDate..... )
    • 事件盡可能以 handle... 開頭命名 (eg: handleChange....)
    • 組件私有的自定方法以下劃線 _..... 開頭命名 (eg: _getLocalDate...... )
  6. react 概念大全
    事件系統(tǒng) + 表單應(yīng)用 + 樣式處理 + 組件通訊 + 組件抽象 + 組件性能優(yōu)化 + 動畫 + 自動化測試

一:react 基本概念解析

  1. react 描述 DOM 的 方式 (JSX)jsx 其實(shí)就是 JavaScript 對象
  • 在 javascript 中使用類似于 HTML 結(jié)構(gòu)和信息的語法為 JSX 語法。

    很容易轉(zhuǎn)換編譯成為 于 HTML 信息的 JavaScript 表示形式( `HTML 的 對象形式` )。
    
    可以根據(jù)平臺 編譯成為 第三方頁面 UI 結(jié)構(gòu)
    
jsx編譯過程.png
  • ReactDOM 解析
    ReactDOM 是 react 提供的 WEB 頁面構(gòu)建對, 在 移動端 該對象是 ReactApp
    ReactDom 有三個方法:
    findDomNode( this ) // 用于獲取頁面中的DOM 元素
    UnmountComponentAtNode()
    render() // 用于頁面渲染

  • ref 和 findDomNode 獲取頁面元素辨析
    ref 添加到 Component 上獲取的是 Component 實(shí)例,
    ref 添加在 原生的 HTML 上獲取的是 DOM 節(jié)點(diǎn)

        findDomNode 當(dāng)參數(shù)是 DOM 時 就返回一個 DOM( 貌似沒什么用 )
        findDomNode 當(dāng)參數(shù)是 Component 時返回 Component 中的 render 中的 DOM
        
        <div>
            <div ref={div => {
                  this._div = div
                 }}>app
            </div>
            <Child ref={child => this._child = child}/>
            <button onClick={()=> {
                        console.log(ReactDOM.findDOMNode(this._div) === this._div);
                        console.log(ReactDOM.findDOMNode(this._child));
                 }}>log refs
            </button>
        </div>
    

    特點(diǎn)
    1. react 使用 jsx 描述 DOM / UI 結(jié)構(gòu)
    2. jsx 預(yù)防在編譯階段 會轉(zhuǎn)換為 DOM 的 JavaScript 表現(xiàn)形式
    3. ReactDom 對象只有一個作用 ---> 負(fù)責(zé)將 JavaScript 對象 渲染成為 真正的頁面 DOM
    4. 在渲染過程中 react-dom( web ) ,react-canvas( canvas ) ,react-app (react-native) 可分別將該 JS 對象渲染到不同的平臺上

  1. render 函數(shù)中都可以寫什么

render 函數(shù)能且只能 返回一個 jsx 對象, 就是必須 返回一個值,并且這個值 是一個 類似于 DOM 的 jsx 語法

  • jsx 結(jié)構(gòu)中可以使用 { } ( 大括號 ) 插入 表達(dá)式

    { } 大括號中 可以放置任何表達(dá)式內(nèi)容( 包括 函數(shù),jsx 結(jié)構(gòu),變量,對象,表達(dá)計(jì)算式 )

      ...
      render () {
          const isGoodWord = true
          return (
                      <div>
                            React 小書
                            {
                                // jsx 中的注釋 只能寫在 大括號中
                                // 下面表示一個三目表達(dá)式
                                // 這里不能寫 JavaScript 的 多行表達(dá)式
                                isGoodWord ? <strong> is good</strong> : <span> is not good</span> 
                            }
                            {
                                  // 下面表示一個自執(zhí)行函數(shù),函數(shù)中可以做任何你想做的事,也可以有多行代碼
                                 (function() {
                                           .... doSomething
                                 })
                            }
                      </div>
                  )
      }
      ...
    
  • jsx 結(jié)構(gòu)中的 null 表示什么都不顯示,相當(dāng)于忽略了該表達(dá)式的插入,可以使用這個特性來 隱藏元素

  • jsx 結(jié)構(gòu)整體當(dāng)做變量用于 參數(shù)傳遞或者使用

    jsx 語法其實(shí)就是一個個 js 的對象,所以可以使用任何變量能使用的方式傳遞或者使用它們

     ...
      render () {
          const isGoodWord = true
          const goodWord = <strong> is good</strong>    // 這是一個 jsx 變量
          const badWord = <span> is not good</span>   // jsx 變量還可以當(dāng)做 函數(shù)參數(shù)傳遞
          return (
              <div>
                    React 小書
                    {isGoodWord ? goodWord : badWord}
              </div>
         )
      }
      ...
    
  • 在 render 的 {} 中 可以使用 map 等 返回 DOM LIST 的函數(shù)方法

      // 必須返回一個 表示 DOM LIST 
     const arr = [1, 2, 3, 4, 5];
     render () {
          return (
                <select>
                      this.arr.map((item) => 
                          <option>item</option>
                      )
                </select>
            )
      }
      ...
    
  • jsx 中的 三元表達(dá)式 其實(shí)就是一句完整的表達(dá)式,所以可以被 識別

  1. jsx 語法中 注釋的寫法

    注釋只能寫在 JavaScript 表達(dá)體 中( 即只能 寫在 { } 大括號中 ),寫在 大括號外面的注釋不被識別
    要是真的想寫注釋,可以給某個或者某條語句外面添加一個 大括號,然后在進(jìn)行注釋

  2. 組件嵌套

組件和組件之間可以 嵌套使用。但是所有的自定義組件都必須是以 大寫字母開頭的組件。

  1. 事件系統(tǒng)

    • 每個 jsx 元素上面都可以自己定義 on* 類型的事件監(jiān)聽函數(shù),只能用在普通的 html 元素標(biāo)簽上,不能使用在自定義的元素標(biāo)簽上

    • 每個事件監(jiān)聽函數(shù) 都有一個默認(rèn)的 event 對象。一個經(jīng)過 react 包裝的 event 對象

    • react 的事件代理機(jī)制
      react 將事件處理函數(shù)統(tǒng)一綁定在最外層上面
      react 對于原生的 DOM 節(jié)點(diǎn)可以書寫原生的事件
      ** 特別注意 **: 因?yàn)?react 的事件代理機(jī)制,注意 stopPropagation() 阻止事件冒泡的時機(jī)

    • 注意 每個 事件監(jiān)聽函數(shù) 若內(nèi)部有使用到 this 的情況,需要在聲明函數(shù)的地方,動態(tài)的綁定 this

      // bind this 的時候 可以 傳遞默認(rèn)的 參數(shù)
      render () {
          return (
              <h1 onClick={this.handleClickOnTitle.bind(this, 'Hello')}>React 小書</h1>
          )
      }
      
    • react 的 this 自動綁定區(qū)域
      A. class 內(nèi)部自動綁定 this ( class 的 { } 大括號這一層級 自動綁定 this )
      B. 構(gòu)造函數(shù) constructor 中沒有自動綁定this
      C. 箭頭函數(shù)自動綁定this
      D. 使用 bind 顯示綁定 this

  2. state 的 使用

    • 每次調(diào)用 setState 都會觸發(fā) react 的重新渲染,并且重新調(diào)用 render 方法 **
  • setState 函數(shù)執(zhí)行時可以接受一個參數(shù)(prevState)
  • 多個 setState 執(zhí)行需要合并時 需要 prevState 參數(shù)的幫忙。并且 react 會將 多個 setState 操作合并為一個最終的狀態(tài)進(jìn)行一次性渲染
  • react 自己的 diff 算法保證只會渲染更改的地方
  1. props 的使用
  • props 帶來更好的復(fù)用性和 可配置性

  • defaultProps設(shè)置組件默認(rèn)的 props, 和 this.props 獲取配置參數(shù),設(shè)定 組件的默認(rèn) props 數(shù)據(jù)

  • 組件內(nèi)部一旦傳遞進(jìn) props 不可以在組件內(nèi)部更改 props
    但是 組件內(nèi)部 可以獲取 props. 將其賦予 state 或者 其他變量進(jìn)行數(shù)據(jù)的增刪改。

組件的生命周期


  1. 前端的狀態(tài)數(shù)據(jù)管理, - 狀態(tài)提升

將組件之間共享的數(shù)據(jù)抽象并提取出來放到最近的 公共父節(jié)點(diǎn)上,然后通過 props 將數(shù)據(jù)傳遞給子組件, 這樣就是一個狀態(tài)數(shù)據(jù)的提升。

那么問題來了? 怎樣管理 多個層次的組件 所依賴的狀態(tài)呢 ?
( ** 請大家關(guān)注 context 和 redux 的相關(guān)內(nèi)容 ** )

  1. 組件的基礎(chǔ)生命周期
組件聲明周期過程.png

react 將組件渲染 并塞到 DOM 元素中然后繪畫在頁面上的過程稱為組件的掛載

所以 由掛載的過程你可以很好的理解下面的組件處理過程

constructor() // 初始化狀態(tài)數(shù)據(jù)
componentWillMount() // 組件的掛載過程
render()
// 構(gòu)造 DOM 元素 插入頁面
componentDidMount() // 組件的掛載過程
。。。。。
// 即將從頁面中刪除元素
componentWillUnmount()
// 從頁面中刪除元素

以上 的幾個生命周期 都是 組件的 第一階段的狀態(tài)管理函數(shù)

  • 一般的 getDefaultProps 和 getInitialState 都會放在 constructor 中完成
  • 組件的隱藏 會觸發(fā) 頁面的 componentWillUnmount() 函數(shù),所以,在頁面被隱藏時要注意剩余數(shù)據(jù) 的處理。
  • componentWillMount() 函數(shù)多用于組件的啟動,eg: ajax, localStore數(shù)據(jù)的拉取,定時器的啟動,等工作。
  • componentDidMount() 函數(shù)用于依賴 DOM 的事件動作或者其他。eg: 動畫的啟動需要依賴 DOM. componentWillMount 的時候 DOM 還沒有掛載完成,所以動畫的啟動需要放在 DidMount 函數(shù)中完成
  1. 組件更新的生命周期

    shouldComponentUpdate(nextProps, nextState) 返回一個 boolean 數(shù)據(jù)。 用于控制組件是否 重新渲染。
    componentWillReceiveProps(nextProps). 多用于處理父組件傳遞過來的 props
    componentWillUpdate(); 組件開始更新之前調(diào)用。
    componentDidUpdate(); 組件更新并且重新渲染到 DOM 之后調(diào)用。

  2. ref 的作用

ref 屬性用于獲取已經(jīng)掛載的 DOM 節(jié)點(diǎn)( 類似于為元素添加 id 屬性,用于表示元素 )
refs 用于引用已經(jīng) 標(biāo)識的 DOM 節(jié)點(diǎn),獲取其 對象的 屬性 和 方法

** 注意: ** 多余 的 DOM 操作 會產(chǎn)生代碼的噪音,不推薦大量使用 ref 操作 DOM

ref 版本改動:標(biāo)識 DOM 節(jié)點(diǎn)的 ref由原來的字符串改為一個回調(diào)函數(shù)
舊版本 <input ref="myinput" />
新版本 <input ref={(input)=>{this.myinput=input;}}/> 可以額外有一個參數(shù) 參數(shù)有妙用

  1. props.children 和 自定義標(biāo)簽元素中 添加 額外的 HTML DOM 元素

普通的標(biāo)簽元素中內(nèi)嵌的 DOM 元素可以直接添加。但是自定義標(biāo)簽組件怎講將內(nèi)嵌的 DOM 內(nèi)容傳遞到下一層呢?

我們使用 props.children 可以獲取到上層的 自定義標(biāo)簽中的內(nèi)嵌的 DOM 元素

  1. jsx 中任何的 html 格式的 代碼都會被轉(zhuǎn)義掉,為了防止 xss 攻擊

    為了顯示 帶有 html 標(biāo)簽的元素我們需要用到元素的 dangerouslySetInnerHTML (
    這個只是元素的一個屬性

    .....
    render() {
          renturn (
             <div
                    className="edit-html"
                     // 按照下面的方法設(shè)置元素的 html 的內(nèi)容
                    dangerouslySetInnerHtml={ { __html: this.state.content } }
             >
        ) 
    }
    .....
    
  2. propsTypes 和 組件的參數(shù)驗(yàn)證
    JavaScript 是弱類型的語言,但是為了 ** 防止和校驗(yàn)上一層傳遞過來數(shù)據(jù)的正確性,我們使用 PropTypes 來做數(shù)據(jù)類型的校驗(yàn)相當(dāng)于為數(shù)據(jù)添加數(shù)據(jù)類型,強(qiáng)類型的數(shù)據(jù) **

     import React, { Component, PropTypes } from 'react'
     ....
     class ChildComponent extends Component {
           // 下面這些是固定的 書寫格式
           static propsTypes = {
                 parentAttr: PropTypes. object,
                 parentArr: PropTypes.array
           }
           .........
     }
     ......
    
  3. 高階組件就是一個函數(shù),你傳遞給他一個組件對象,他返回給你一個經(jīng)過包裝的組件對象
    ** 相當(dāng)于在原始組件之上 添加了一層經(jīng)過封裝的父組件 ** 功能性的封裝

    ** 作用:**

    • 組件狀態(tài)提升
      將子組件需要操作的數(shù)據(jù)交給父組件來管理,然后通過 props 向下傳遞數(shù)據(jù)。此為 狀態(tài)提升
      當(dāng)某個數(shù)據(jù)/狀態(tài) 被多個組件依賴/使用 時,應(yīng)該通過狀態(tài)提升來管理

    • 高階組件本質(zhì)就是為了組件之間的復(fù)用,將重復(fù)的代碼 操作放在高階組件中,下面的基本組件就可以復(fù)用了

       比如數(shù)據(jù)的 ajax 的讀取,事件的統(tǒng)一操作等
      
    • 高階組件中 通過 props 傳遞數(shù)據(jù)

    • 高階組件可以很好的實(shí)現(xiàn) Smart 組件( 依賴數(shù)據(jù)操作的組件/ 高階組件 ) 和 Dumb 組件( 只需要上層數(shù)據(jù)props的純組件 ) 的分離

      Smart 組件和 Dumb 組件( 或者說高階組件 )的出現(xiàn),很好的實(shí)現(xiàn)了 react 的 mvc 結(jié)構(gòu),達(dá)到了高層次的 組件的復(fù)用。

高階組件知識點(diǎn)
1. 高階組件 本質(zhì)就是一種 組件的 mixin 模式
1. es7 的裝飾著模式可以用來擴(kuò)展高階組件
2. 一個 Smart 組件可以被多個高階組件裝飾,并且按照順序執(zhí)行

高階組件.png
  1. react 的 context 作為全局的對象,有自己獨(dú)特的寫法

    ** context 必須和 propType 強(qiáng)制數(shù)據(jù)類型 共同使用 **

    • 強(qiáng)制數(shù)據(jù)類型
      import React, { Component, PropTypes } from 'react'
      ......
      static propsTypes = {
      themeColor: PropTypes. string
      }

    • 定義context 時的寫法

      import React, { Component, PropTypes } from 'react'
      ....
      class ParentComponent extends Component {
          // 下面這些是固定的 書寫格式
          static propsTypes = {
                themeColor: PropTypes. string
          }
          .........
          // 這里設(shè)置了 本組件包括其 所有子組件的 context 
          getChildContext () {
                 return { themeColor: this.state.themeColor }
          }
      }
      ......
      

    context 在定義時,必須有兩個步驟
    聲明屬性的數(shù)據(jù)類型
    設(shè)置獲取全局 Context 的方法 getChildContext

    • 使用 context

            import React, { Component, PropTypes } from 'react'
            ....
            class ChildComponent extends Component {
                  static propsTypes = {
                        themeColor: PropTypes. string
                   }
                  render () {
                          return (
                                <div  style={{ color: this.context.themeColor }}>context 的獲取使用地方</div>
                          )
                   }
            }
      

    context 在使用時必須有兩個步驟
    聲明要使用的 context 數(shù)據(jù)類型
    使用 this.context.屬性 獲取屬性的值

context 使用步驟繁雜是有原因的
1. context 作為全局擁有的對象,必須保證其數(shù)據(jù)的正確性。
2. react 官方不推薦使用 context, 進(jìn)而希望大家能夠使用更為友好的 Redux, Mobx等

React 組件進(jìn)階


  1. react 理念分析

    • React 的組件本質(zhì)是創(chuàng)建了一個對象,由框架本身添加了 10 個聲明周期函數(shù)( 其實(shí)就是普通的函數(shù),只是有執(zhí)行順序、觸發(fā)時機(jī)、優(yōu)化處理等特點(diǎn) )
      具體參見 React 的最初寫法 React.createClass({ .... }), 中間是一個對象

    • 聲明周期函數(shù),就是對象中的普通函數(shù)
      傳值 + 操作處理 + 返回值

    • react 特點(diǎn):
      1. 簡潔: 足夠的簡潔,其本身只有自己的 api
      2. 非聲明式的單項(xiàng)數(shù)據(jù)綁定
      3. ** 面向 HTML5, 專注視圖層操作 ** 將 JavaScript 和 HTML5 整合在一起。
      4. 高性能的密集 DOM 操作
      5. 支持后端渲染。
      6. 跨平臺,一種書寫,能夠編譯出多種結(jié)果 ** ReactNative **

      react 函數(shù)式編程 ( 小函數(shù)編程 )
      1. 盡可能抽象出公共使用的小函數(shù)。
      2. 在一個龐雜的 邏輯體 中能夠提取出 功能小函數(shù)

    • 組件化
      狹義的組件化:ui組件 ---> 具體的組件( Tabs 組件 / Dropdown 組件 )
      廣義的組件化: 業(yè)務(wù)數(shù)據(jù) + UI 組件的組合使用

      組件化的發(fā)展進(jìn)程

      DOM操作為主( 根據(jù)邏輯改變 DOM 結(jié)構(gòu) ) --> MVC( 數(shù)據(jù)和界面解耦 ) --> 小組件( 數(shù)據(jù) + 界面 + 樣式的結(jié)合體 eg: angular 指令 ) ----> HTML5 的引入 ( javascript + HTML + css 合為一體)

      HTML Templetes --> custom Element --> shadow DOM --> HTML Imports

    • ** 非常重要:**
      ** 組件封裝的進(jìn)程其實(shí)就是面向?qū)ο蟮乃枷胫鸩匠墒?* (通過實(shí)例化的方法制造對象

      一個組件的對象實(shí)例: ( 基本的封裝性 + 簡單的聲明周期 + 明確的數(shù)據(jù)流動 )

  2. 表單組件

    表單組件分為受控組件和非受控組件
    受控組件:依靠 state 和內(nèi)部事件 改變狀態(tài)的組件,有很強(qiáng)的耦合性,復(fù)用性不高

       非受控組件,通過 defaultProps, props 傳值的組件,復(fù)用性好
               非受控組件可以通過 事件和 ref 向上傳遞數(shù)據(jù)
    
  3. 組件通訊 ---> 事件訂閱
    EventEmitter

  4. 組件性能優(yōu)化

    1. 引入純函數(shù)( pureRender 函數(shù)或者 Smart組件 )

    2. 使用 數(shù)據(jù)對比決定 純函數(shù)組件是否渲染 shouldComponentUpdate()

    3. 引入不可變對象 或者 es6 對象擴(kuò)展 進(jìn)行數(shù)據(jù)對比

         Immutable 不可變對象,對 Immutable 對象的 增 刪 改 都會生成一個新對象,類似于對象的深拷貝,但是比對象的深拷貝效率要高
      
         es6 對象擴(kuò)展 和 對象/數(shù)組的解構(gòu)賦值,也能夠得到一個新的對象
      
    4. Immutable 解析

      ** Immutable 可以提供一種全新的數(shù)據(jù)對比和生成形式,類似于 es6 的對象擴(kuò)展 和 解構(gòu)賦值 **

         Immutable 三種數(shù)據(jù)類型 
         Map: 對應(yīng)于 `Object`, 鍵值對集合
         List :   對應(yīng)于 `Array` 有序的重復(fù)列表
         ArrayList: 無序不可重復(fù)的列表
      
         // 特性應(yīng)用實(shí)例
         import { Map, List, Arraylist } from 'immutable'
         ....
         this.setSatate({
                 data: Map({ times: 0 })      // 得到一個新的 Immutable 對象
         })
      

      Immutable 方法應(yīng)用實(shí)例 ( Immutable.is 可以用來進(jìn)行比較,比 === 全等的效率高 )

         import { is } from 'immutable'
         .....
         shouldComponentUpdate(nextProps, nextState) {
               if( is( nextProps.attr, nextState.attr ) )
                     return false;
              ......
         }
      

.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容