1. 程式人生 > 其它 >react-5-從jsx到類元件的生命週期

react-5-從jsx到類元件的生命週期

react 筆記

jsx中繫結this

為什麼this會是undefined ?

  1. 可以使用bind方式繫結this

<button onClick={this.sayHi.bind(this)}>{this.state.btnDes}</button>

  1. 可以使用箭頭函式方式繫結this

<button onClick={() => this.sayHi()}>{this.state.btnDes2}</button>

jsx中的列表渲染

一般的,都是使用map進行列表渲染,同時返回一個jsx-dom

    <ul>
          {/* 在這裡,一般用map來進行列表渲染 */}
          {
            this.state.movies.map((item, index) => <li onClick={() => this.getItme(item)} key={index}>{item}</li>)
          }
    </ul>

計數器案例

  1. setState的函式形式:

傳遞一個函式可以讓你在函式內訪問到當前的 state 的值。因為 setState 的呼叫是分批的,所以你可以鏈式地進行更新,並確保它們是一個建立在另一個之上的,這樣才不會發生衝突

 this.setState((pre, next) => {
      console.log(pre, next);
      return {
        val: data
      }
    })

幾點提示

pre : state更改前的上一次狀態
next : state更改後的狀態
函式式必須要return一個物件,分別對應state內的鍵值對

  1. 繫結屬性

繫結屬性類似原生小程式,如
<input onChange={(e) => { this.changeVal(e) }} value={this.state.val ? this.state.val : 0} />

  1. react並沒有雙向繫結,因而要使用e事件物件來找到值

  2. 關於num++ 與num+1
    要使用num+1

在使用setState的時候不能使用num++,否則會導致修改失敗 ,並且在事件觸發時state也只會保持原值

JSX語法

描述:jsx是js的拓展語法,想要使用jsx ,需要給script標籤中新增 type="text/babel"

屬性

  1. jsx規範
  2. jsx頂部只允許有一個根元素,即便是空標籤也可以
  3. jsx外層包裹一個小括號,一來方便閱讀,二來可以換行書寫
    3.jsx中的標籤可以是單標籤,也可以是雙標籤,但如果是單標籤,需要/>結尾,如<img />, <div />
  4. jsx註釋

通常使用{/* 這裡是註釋 */}來表示,在jsx上下文環境下,ctrl+/可以自動生成註釋行

  1. jsx嵌入變數
    *. jsx中可以正常顯示這些型別: string,number,array
    *. jsx中一般不能渲染以下資料型別(會顯示dom,但不會顯示dom的內容)

    1. null undefined

    如果必須要讓null,undefined顯示,可以使用String(null/undefined)的方式,也可以直接讓其加''

    2.boolean

    如果必須要對bool顯示,可以使用bool.tostring()方法變成字串

    1. obj

    物件不能作為jsx的子類 =》 不允許直接在jsx中渲染obj本身,但可以渲染obj內部的key-value

jsx嵌入運算子

在render函式內,可以使用解構的方式將state內的資料拿出來

render() {
  const {cannotShow1,cannotShow2} = this.state
  return(
    <div>
      <p>render本質上是一個函式,只不過return了一個特殊的物件<p/>
    </div>
  )
}

jsx可以嵌入以下:

  1. 表示式

{fN + lN}

  1. 數學程式
  2. 三目運算
  3. 邏輯與
  4. 函式呼叫

如果是函式呼叫,則可以有vue-filter/computed(?有嗎 有待考證)

jsx繫結屬性

  1. 一般的可以直接使用
<p title={'這是' + '繫結屬性'}> </p>
  1. 但有的會與js本身的關鍵字/保留字衝突,此時要自主更換,遵循jsx規約
    如:
    class => className
    for => htmlFor
jsx繫結class(重點)

jsx下的class要用className替代,想要繫結className樣式,需要使用大括號語法

元素普通的class名,用引號包裹即可

<span className='hehehe'>這裡是普通class</span>

被綁定了class的元素,外部需要用大括號,這個大括號是jsx語法,普通class與三木運算class需要保留間隔

<span className={'hhh jjj ' + (isTrue ? 'istrue' : '')}>繫結class時,外部包裹大括號,因為class也是屬性</span>

jsx繫結style(重點)

style屬性必須是一個物件格式,當key是兩個字元時,遵循小駝峰格式,value不加引號時會被認為是一個變數
<span style={{ border: '1px solid red', background: 'red' ,}}>繫結style</span>

jsx繫結事件

jsx繫結事件,事件名 依舊要使用小駝峰標識

jsx如果不繫結this的話,將不能找到類元件本身的constructor裡的state(提示state of undefined),

想要找到正確的this值,需要繫結this,有以下三種方法

  1. jsx中顯式繫結this
    <div onClick={this.sayHi.bind(this)}></div>

缺陷,易導致冗餘程式碼產生

  1. 構造器內,super下繫結this
constructor(props){
  super(props)
  {/*本質上是給原來的函式事先繫結後this,然後又重新賦值給這個函式 
      在之前比較常用
  */}
  this.sayHi = this.sayHi.bind(this)
}   
  1. jsx中給dom繫結事件時使用箭頭函式
<div onClick={() => this.sayHi()}>11111</div>

請注意:箭頭函式下,內部函式必須要加小括號表示執行!

  1. 宣告函式時,不再宣告普通函式,而是宣告箭頭函式

原因:箭頭函式在宣告時無法繫結this,因而自動一層層向上尋找值(隱式),這種本質上是使用es6中給類新增屬性的方法 class fileds

 //外部觸發的函式在宣告時使用箭頭函式

 sayHi = () => {
   console.log(this.state.isTrue)
 }

 <div onClick={this.sayHi}>11111</div>
jsx什麼時候寫大括號?

大括號裡寫什麼 取決於你希望在這個大括號裡返回什麼

條件判斷

react邏輯判斷遵循js原生邏輯
*一: 如果邏輯很多,可以使用if判斷,
*二: 如果邏輯很少,可以使用三目運算子判斷,
*三: 三木運算子與&&邏輯與, v-if / v-show
*四: 本質上是&&邏輯與完成了與v-if相同的效果,即在dom中先刪除再生成
*五: 想要完成v-show,可以操作style的display屬性

map與filter的組合渲染
  1. 過濾再擷取

很多時候只希望渲染符合條件的所有list,因而可以先使用filter再使用map的方式

{/*
先使用filter過濾不符合條件的,此時該陣列內只剩下符合條件的,然後再使用map渲染列表
*/}
<ul>
          {
            numArr.filter(item => item > 90)
              .map(v => <li>{v}</li>)
          }

</ul>

2.過濾擷取再渲染

<ul>
          {
            numArr.filter(item => (item > 30) && (item < 100))
              .slice(0, 4)
              .map(v => <li>{v}</li>)
          }

</ul>

總結:jsx允許在map渲染前對原陣列進行任何js允許的操作

jsx原始碼

  1. jsx的本質
    在普通script標籤中無法寫jsx的原因是,jsx最終要經過ReactDOM.createElement()將其編譯成語法糖
    ReactDOM.createElement(type,config,children)

傳入三個引數:
*. type: 當前ReactElement傳入的型別
如果是元素標籤,那麼就用字串表示'div'
如果是元件標籤,那麼就直接使用元件名稱
*. 當前ReactEle的屬性以及事件,以鍵值對物件的方式進行儲存
*. children
存放在ReactEle中的內容,以children陣列的方式進行儲存
如果有多個子元素,需要用babel進行轉換

問題:為什麼引數第三個屬性是一個引數並且不是一個可變引數,但是編譯後卻並不報錯?

使用auguments來對後面的引數進行一一匹配:
const sonArr = auguments.length - 2 //減去2的原因是減去精準匹配引數1,精準匹配引數2

通過createElement()最終生成了一顆js dom樹,這棵樹(js物件)就是虛擬dom樹 React.render負責將這顆dom樹對映到指定的真實dom節點上,從而將虛擬dom樹變成了真實dom樹結構(瀏覽器中),RN中其實都相同,只是沒有渲染真實dom,而是渲染成了安卓、ios的原生控制元件,taro?
流程:jsx => createElement(jsx) => render(createElement(jsx),DOM) = > 真實dom
render.dom將虛擬dom與真實dom一一對映,這個叫做對映

為什麼要使用虛擬dom
  1. 很難追蹤狀態發生的改變
  2. 操作真實dom效能較低

    dom操作會引起瀏覽器的迴流和重繪
    設計原則: 元資料的不可變性,【1.只允許使用setstatus修改資料,2.儘量生成新資料而不修改元資料(如果是引用型別,可以進行淺拷貝,然後再賦值進去)】

以render函式為界:
功能函式一般放在render函式後面
元件函式放在render前面

react-cli 中package.json的版本區別

 "dayjs": "^1.10.5" 

1.10.5:表示目標庫始終使用這個版本
^1.10.5:表示小版本更新【"5"可變】

弊端:小版本更新也可能造成版本之間誤差,yarn.lock檔案表示安裝的具體詳細版本

yarn eject的作用

暴露react-cli的webpack配置,但這是不可逆的
執行後會暴露config目錄和script目錄
執行後package.json會暴露react內部的一些依賴庫
執行後package.json的script每一項的value會發生變化:

// 之前是這樣
  "start": "react-scripts start --open",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject"

// 現在是這樣  script目錄:執行eject後暴露出的目錄
  "start": "node script/start.js --open",
  "build": "node script/build.js",
  "test": "node script/test.js",

修改src原始碼會直接熱更新,修改config目錄、script目錄時需要重新執行

vscode自動補全jsx外掛

htmltagwrap

react元件的型別

  1. 根據元件的定義方式 分為 函式式元件與類元件
  2. 根據元件內部是否需要維護,分為無狀態元件與有狀態元件
  3. 根據元件的不同職責,可以分為展示型元件和容器型元件

以上定義方式有很多重疊,但主要都關注資料邏輯與ui展示的分離

  1. 函式元件,無狀態元件,展示型元件主要關注UI的展示
  2. 類元件,有狀態元件,容器型元件主要關注資料邏輯

jsx中標籤規範

普通標籤不允許大寫,jsx會認為是未定義的元件

元件規約

  1. 凡是元件必須大寫字元開頭
  2. 類元件需要繼承React.Component(16.3後可直接繼承Component)
類元件
  1. constructor是可選的,通常在內部初始化資料(this指向,定義元件變數,接收父元件資料)
  2. constructor中的this.state用於初始化元件內部需要的資料(es7中,可以在constructor外部使用state={xx:xxx}達到相同結果)
  3. render是類元件中唯一需要實現的方法

函式式元件

  1. 沒有內部狀態
  2. 沒有this物件

render函式的返回值

不管是函式式元件還是render函式

  1. react元素

  2. 陣列或者fragments:=》 使得render方法可以返回多個元素

不允許返回物件!

外掛快捷鍵~ ES7 React/Redux/React-Native/JS snippets

  1. rcc => 生成類元件
  2. rfc => 生成函式式元件
  3. imd => 從庫中全部匯入
  4. imn => 匯入庫(如css)
  5. imd => 從庫中匯入某個變數函式
  6. cp => 從props中解構
  7. cs => 從status中解構
  8. clo => console.log(obj,obj) //obj此時被選中
  9. imr→ import React from 'react'
  10. imrc => import React,{Component} from 'react'

多退少補

生命週期

人或物從誕生到消亡的整個過程

react的生命週期分為三種:

  1. mount: 元件初次被渲染的階段(mounting)

constructor :

comoponentDidmount:

  1. updata: 元件資料更新,重新更新渲染的階段updating

render: 接收props或者setstatus或者強制重新整理dom時都會重新呼叫render函式

componentDidUpdate

  1. unmount:元件從dom樹中被移除的階段unmounting

componentWillUnmount

執行順序 =》 constructor => render => react內部開始更新或掛載元件 =》 componentDidmount/componentDidUpdate

類元件版父子元件

import { Component } from 'react'
class Son extends Component {
  constructor(props) {
    super(props)
    this.state = {}
  }
  render() {
    return (
      <div>
        <p>我是子元件</p>
      </div>
    )
  }
}
class App extends Component {
  constructor(prop) {
    super(prop)
    this.state = {
    }
  }
  render() {
    return (
      <div>
        <p>這是父元件</p>
        <Son />
      </ div>
    )
  }
}
export default App

在一個大元件檔案裡,一個小元件可以定義在這個元件裡,然後直接匯入大元件內部即可,請注意: 必須保證是純函式!

純函式:在輸入時就能保證輸出的資料型別和值,且無副作用

待續。

作者:致愛麗絲 出處:https://www.cnblogs.com/hjk1124/ 本文版權歸作者和部落格園共有,歡迎轉載,但必須在文章頁面給出原文連結並標名原文作者,否則保留追究法律責任的權利。