react-5-從jsx到類元件的生命週期
react 筆記
jsx中繫結this
為什麼this會是undefined ?
- 可以使用bind方式繫結this
<button onClick={this.sayHi.bind(this)}>{this.state.btnDes}</button>
- 可以使用箭頭函式方式繫結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>
計數器案例
- setState的函式形式:
傳遞一個函式可以讓你在函式內訪問到當前的 state 的值。因為 setState 的呼叫是分批的,所以你可以鏈式地進行更新,並確保它們是一個建立在另一個之上的,這樣才不會發生衝突
this.setState((pre, next) => {
console.log(pre, next);
return {
val: data
}
})
幾點提示
pre : state更改前的上一次狀態
next : state更改後的狀態
函式式必須要return一個物件,分別對應state內的鍵值對
- 繫結屬性
繫結屬性類似原生小程式,如
<input onChange={(e) => { this.changeVal(e) }} value={this.state.val ? this.state.val : 0} />
-
react並沒有雙向繫結,因而要使用e事件物件來找到值
-
關於num++ 與num+1
要使用num+1
在使用setState的時候不能使用num++,否則會導致修改失敗 ,並且在事件觸發時state也只會保持原值
JSX語法
描述:jsx是js的拓展語法,想要使用jsx ,需要給script標籤中新增
type="text/babel"
屬性
- jsx規範
- jsx頂部只允許有一個根元素,即便是空標籤也可以
- jsx外層包裹一個小括號,一來方便閱讀,二來可以換行書寫
3.jsx中的標籤可以是單標籤,也可以是雙標籤,但如果是單標籤,需要/>
結尾,如<img />
,<div />
- jsx註釋
通常使用
{/* 這裡是註釋 */}
來表示,在jsx上下文環境下,ctrl+/可以自動生成註釋行
-
jsx嵌入變數
*. jsx中可以正常顯示這些型別: string,number,array
*. jsx中一般不能渲染以下資料型別(會顯示dom,但不會顯示dom的內容)- null undefined
如果必須要讓null,undefined顯示,可以使用String(null/undefined)的方式,也可以直接讓其加''
2.boolean
如果必須要對bool顯示,可以使用bool.tostring()方法變成字串
- obj
物件不能作為jsx的子類 =》 不允許直接在jsx中渲染obj本身,但可以渲染obj內部的key-value
jsx嵌入運算子
在render函式內,可以使用解構的方式將state內的資料拿出來
render() {
const {cannotShow1,cannotShow2} = this.state
return(
<div>
<p>render本質上是一個函式,只不過return了一個特殊的物件<p/>
</div>
)
}
jsx可以嵌入以下:
- 表示式
{fN + lN}
- 數學程式
- 三目運算
- 邏輯與
- 函式呼叫
如果是函式呼叫,則可以有vue-filter/computed(?有嗎 有待考證)
jsx繫結屬性
- 一般的可以直接使用
<p title={'這是' + '繫結屬性'}> </p>
- 但有的會與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,有以下三種方法
- jsx中顯式繫結this
<div onClick={this.sayHi.bind(this)}></div>
缺陷,易導致冗餘程式碼產生
- 構造器內,super下繫結this
constructor(props){
super(props)
{/*本質上是給原來的函式事先繫結後this,然後又重新賦值給這個函式
在之前比較常用
*/}
this.sayHi = this.sayHi.bind(this)
}
- jsx中給dom繫結事件時使用箭頭函式
<div onClick={() => this.sayHi()}>11111</div>
請注意:箭頭函式下,內部函式必須要加小括號表示執行!
- 宣告函式時,不再宣告普通函式,而是宣告箭頭函式
原因:箭頭函式在宣告時無法繫結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的組合渲染
- 過濾再擷取
很多時候只希望渲染符合條件的所有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原始碼
- 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
- 很難追蹤狀態發生的改變
- 操作真實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元件的型別
- 根據元件的定義方式 分為 函式式元件與類元件
- 根據元件內部是否需要維護,分為無狀態元件與有狀態元件
- 根據元件的不同職責,可以分為展示型元件和容器型元件
以上定義方式有很多重疊,但主要都關注資料邏輯與ui展示的分離
- 函式元件,無狀態元件,展示型元件主要關注UI的展示
- 類元件,有狀態元件,容器型元件主要關注資料邏輯
jsx中標籤規範
普通標籤不允許大寫,jsx會認為是未定義的元件
元件規約
- 凡是元件必須大寫字元開頭
- 類元件需要繼承React.Component(16.3後可直接繼承Component)
類元件
constructor
是可選的,通常在內部初始化資料(this指向,定義元件變數,接收父元件資料)- constructor中的
this.state
用於初始化元件內部需要的資料(es7中,可以在constructor外部使用state={xx:xxx}
達到相同結果) - render是類元件中唯一需要實現的方法
函式式元件
- 沒有內部狀態
- 沒有this物件
render函式的返回值
不管是函式式元件還是render函式
-
react元素
-
陣列或者fragments:=》 使得render方法可以返回多個元素
不允許返回物件!
外掛快捷鍵~ ES7 React/Redux/React-Native/JS snippets
- rcc => 生成類元件
- rfc => 生成函式式元件
- imd => 從庫中全部匯入
- imn => 匯入庫(如css)
- imd => 從庫中匯入某個變數函式
- cp => 從props中解構
- cs => 從status中解構
- clo => console.log(
obj
,obj) //obj此時被選中 - imr→ import React from 'react'
- imrc => import React,{Component} from 'react'
多退少補
生命週期
人或物從誕生到消亡的整個過程
react的生命週期分為三種:
- mount: 元件初次被渲染的階段(mounting)
constructor :
comoponentDidmount:
- updata: 元件資料更新,重新更新渲染的階段updating
render: 接收props或者setstatus或者強制重新整理dom時都會重新呼叫render函式
componentDidUpdate
- 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/ 本文版權歸作者和部落格園共有,歡迎轉載,但必須在文章頁面給出原文連結並標名原文作者,否則保留追究法律責任的權利。