日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

React基础学习(第二天)

發(fā)布時(shí)間:2023/12/13 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React基础学习(第二天) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

虛擬DOM

  • JSX 涉及到 虛擬DOM ,簡單聊一下

定時(shí)器渲染問題

// 方法 function render() {//2. 創(chuàng)建react對象let el = (<div><h3>時(shí)間更新</h3><p>{ new Date().toLocaleTimeString()}</p></div>)//3. 渲染ReactDOM.render(el, document.getElementById('root')) }//4. 開啟一個(gè)定時(shí)器, 每秒渲染一次 setInterval(() => {render() }, 1000)

渲染模式 :

/*** 最早的更新模式* 1. 數(shù)據(jù)* 2. 模板* 3. 數(shù)據(jù)+模板 => 真實(shí)的DOM* 4. 數(shù)據(jù)變了 => 最簡單直接的方式 => 最新數(shù)據(jù)+模板 => 新的DOM* 5. 新的DOM 把 舊的DOM完全直接替換掉* 6. 顯示新的DOM** 缺點(diǎn) : 完全替換, 性能不好** 1. 數(shù)據(jù)* 2. 模板* 3. 數(shù)據(jù)+模板 => 真實(shí)的DOM* 4. 數(shù)據(jù)變化了 => 最新的數(shù)據(jù) + 模板 => 新的DOM* 5. 新的DOM 和 舊的DOM 進(jìn)行一一比較, 找到需要更新的地方* 6. 只需要更新需要改變的地方即可** 優(yōu)點(diǎn) : 不再是全部替換掉,* 缺點(diǎn) : DOM比較就有性能問題了 , 會有多余的DOM和屬性進(jìn)行比較(打印一級屬性),有損性能* p 和 p對比 h3 和h3對比(多余的對比)** 1. 數(shù)據(jù)* 2. 模板* 3. 數(shù)據(jù) + 模板 => 虛擬DOM (js對象) => 真實(shí)的DOM* 4. 數(shù)據(jù)發(fā)生改變(zs=>ls) => 最新的數(shù)據(jù) + 模板 => 新的虛擬DOM* 5. 新的虛擬DOM 和 舊的虛擬DOM 通過 diff算法 進(jìn)行比較* 6. 找到有差異的地方,(需要更新的地方)* 7. 更新一下就可以看到最新的DOM了*/
  • 打印屬性 :
let root = document.querySelector('#root')let str = '' let count = 0 for (let k in root) {str += k + ' 'count++ } console.log(str, count)
  • 查看圖片 : 演示對比找差異渲染
  • 文字描述 :
這就是所謂的 Virtual DOM 算法。包括幾個(gè)步驟:- 1.用 JavaScript 對象結(jié)構(gòu)表示 DOM 樹的結(jié)構(gòu);然后用這個(gè)樹構(gòu)建一個(gè)真正的 DOM 樹,插到文檔當(dāng)中 - 2.當(dāng)狀態(tài)變更的時(shí)候,重新構(gòu)造一棵新的對象樹。然后用新的樹和舊的樹進(jìn)行比較,記錄兩棵樹差異 - 3.2 所記錄的差異應(yīng)用到步驟 1 所構(gòu)建的真正的 DOM 樹上,視圖就更新了

DIff 算法

React 中有兩種假定:

  • 1 兩個(gè)不同類型的元素會產(chǎn)生不同的樹
  • 2 開發(fā)者可以通過 key 屬性指定不同樹中沒有發(fā)生改變的子元素

Diff 算法的說明 - 1

  • 如果兩棵樹的根元素類型不同,React 會銷毀舊樹,創(chuàng)建新樹
// 舊樹 <div><Counter /> </div>// 新樹 <span><Counter /> </span>執(zhí)行過程: 刪除 div , 創(chuàng)建 span

Diff 算法的說明 - 2

  • 對于類型相同的 React DOM 元素,React 會對比兩者的屬性是否相同,只更新不同的屬性
  • 當(dāng)處理完這個(gè) DOM 節(jié)點(diǎn),React 就會遞歸處理子節(jié)點(diǎn)。
// 舊 <div className="before" title="stuff"></div> // 新 <div className="after" title="stuff"></div> 只更新:className 屬性// 舊 <div style={{color: 'red', fontWeight: 'bold'}}></div> // 新 <div style={{color: 'green', fontWeight: 'bold'}}></div> 只更新:color屬性

Diff 算法的說明 - 3

  • 1 當(dāng)在子節(jié)點(diǎn)的后面添加一個(gè)節(jié)點(diǎn),這時(shí)候兩棵樹的轉(zhuǎn)化工作執(zhí)行的很好
// 舊 <ul><li>1</li><li>2</li> </ul>// 新 <ul><li>1</li><li>2</li><li>3</li> </ul>執(zhí)行過程: React會匹配新舊兩個(gè)<li>1</li>,匹配兩個(gè)<li>2</li>,然后添加 <li>3</li> tree
  • 2 但是如果你在開始位置插入一個(gè)元素,那么問題就來了:
// 舊 <ul><li>1</li><li>2</li> </ul>// 新 <ul><li>3</li> li3 插入最前面<li>1</li><li>2</li> </ul>執(zhí)行過程: React將改變每一個(gè)子節(jié)點(diǎn),而非保持 <li>1</li><li>2</li> 不變

key 屬性

為了解決以上問題,React 提供了一個(gè) key 屬性。當(dāng)子節(jié)點(diǎn)帶有 key 屬性,React 會通過 key 來匹配原始樹和后來的樹。

// 舊 <ul><li key="1">1</li><li key="2">2</li> </ul>// 新 <ul><li key="3">3</li><li key="1">1</li><li key="2">2</li> </ul>執(zhí)行過程:現(xiàn)在 React 知道帶有key '3' 的元素是新的,對于 '1''2' 僅僅移動位置即可

補(bǔ)充說明:

  • key 屬性在 React 內(nèi)部使用,但不會傳遞給你的組件

  • 推薦:在遍歷數(shù)據(jù)時(shí),推薦在組件中使用 key 屬性:<li key={item.id}>{item.name}</li>

  • 注意:key 只需要保持與他的兄弟節(jié)點(diǎn)唯一即可,不需要全局唯一

  • 注意:盡可能的減少數(shù)組 index 作為 key,數(shù)組中插入元素的等操作時(shí),會使得效率底下 。 如果數(shù)組比較簡單, 開發(fā)中沒有刪除和移動操作,使用 index 也是可以的

組件

組件1 - 函數(shù)組件

基本使用

  • 函數(shù)組件 : 使用函數(shù)創(chuàng)建的組件叫組函數(shù)組件
  • 約定:
    • 約定1 : 組件名稱必須是大寫字母開頭, 也就是函數(shù)名稱需要首字母大寫
    • 約定2 : 函數(shù)組件必須有返回值
      • 不渲染內(nèi)容 : return null
      • 渲染內(nèi)容 : return JSX
    • 約定3 : 只能有一個(gè)唯一的根元素
    • 約定4 : 結(jié)構(gòu)復(fù)雜, 使用() 包裹起來
  • 使用 : 把 組件名 當(dāng)成 標(biāo)簽名 一樣使用
// 函數(shù)組件 function Hello() {// return nullreturn <div>這是我的第一個(gè)函數(shù)組件</div> } // 渲染組件 ReactDOM.render(<Hello />, document.getElementById('root'))

傳參

  • 傳參 :
//1. 頭標(biāo)簽內(nèi)演示 //2. age='30' age是字符串30age={30} age是number 30 ReactDOM.render(<Child name='zs' age={30}/>, document.getElementById('root'))
  • 接收 :
    • 函數(shù)的參數(shù)接收 props
      • funciton Hello (props) { ... }
    • 讀取 : { props.name } 、 { props.age }
    • 注意 :
      • 傳過來的props 不能添加屬性
      • 傳過來的props 不能修改屬性值
    • 也可以直接解構(gòu) props里的屬性
      • funciton Hello ({ name, age }) { ... }

箭頭函數(shù)改造

const Child = () => (<div><div>這是一個(gè)div</div><div>這是一個(gè)div</div></div> )const Hello = ()=> <div>這是哈哈的啊</div>

組件2 - 類組件

基本使用

  • 類組件 : 使用 ES6 中class 創(chuàng)建的組件, 叫類組件
  • 約定 (同 函數(shù)組件)
    • 其他約定1 : 類組件必須繼承自 React.Component 父類 , 然后,才可以使用父類中提供的屬性或方法
    • 其他約定2 : 必須提供 render 方法, 來指定要渲染的內(nèi)容, render 方法必須有返回值
// 2 創(chuàng)建類組件 class Hello extends React.Component {// 鉤子 render() {// return nullreturn <div>這是我的第一個(gè)class組件</div>} }

傳參

  • 傳參 : 同函數(shù)組件一樣
ReactDOM.render(<Child name='zs'/>, document.getElementById('root'))
  • 接收參數(shù)
// 類組件 class Child extends React.Component { constructor(props) { super(props)// 接收方式1console.log(props);}render () { // 接收方式2console.log(this.props);// 解構(gòu)const { name, age } = this.propsreturn <div>哈哈{ this.props.name }</div>} }

ES6 - class

介紹

** es6 之前 創(chuàng)建對象 都是通過構(gòu)造函數(shù) 實(shí)現(xiàn)的, 給原型添加方法, 給實(shí)例添加屬性* es6 之后, 給我們提供了一個(gè)字段 class * 通過class 創(chuàng)建對象 * class :* -: 一類對象, 對象的抽象 , 我們可以通過類創(chuàng)建對象* - 動物 人 * * - 對象: 具體的事物, 它有特征(屬性)和行為(方法)* -//鳥 張三/王春春*/

使用 class 創(chuàng)建對象

  • 使用class 創(chuàng)建一個(gè)類 class Person { }
  • 創(chuàng)建對象 let p = new Person()
  • 添加屬性 在類里面的 constructor() { } 的里面添加屬性
  • 添加方法 直接在類里面添加方法
class Person { constructor() { this.name = 'zs';this.age = 30}say () { console.log('說話了');} }let p = new Person() console.log(p); p.say()

繼承

  • 繼承 : 之前混入, 原型繼承… 都是對象繼承… (對象與對象之間,只要拿過來用就是繼承)
  • class 繼承 : 是 類與類之間的繼承 extends
// 人 class Person {constructor() {this.maxAge= 120} }let p = new Person() console.log(p)// --------------------------------------------- /*** 以后凡是 extends 繼承* 當(dāng)前類里面的 constructor 里面一定要加上super()* 因?yàn)榈讓佣际墙o我們加的super,所以我們才能夠繼承過來,* 如果我們直接寫 constructor,而不寫super,意外著,底層的constructor會被覆蓋掉*/ // 中國人 class Chinese extends Person {constructor() {super() // super 其實(shí)就是調(diào)用父類的constructorthis.name = 'zs'} }let c = new Chinese() console.log(c)

函數(shù)組件和類組件的小結(jié)

  • 函數(shù)組件 : 函數(shù)創(chuàng)建組件
    • 函數(shù)名首字母一定要大寫
    • 把組件當(dāng)成標(biāo)簽使用
    • 函數(shù)內(nèi)部 通過 return jsx
  • 類組件 : 類創(chuàng)建組件
    • 首字母也要大寫
    • 一定要繼承(extends) React.Component
    • 類里面一定要有一個(gè) render 函數(shù)
    • render 函數(shù)里面通過 return jsx
    • 類組件也是當(dāng)成標(biāo)簽一樣使用的

函數(shù)組件和類組件的區(qū)別?

  • 函數(shù)組件 : 沒有狀態(tài)的, 沒有自己的數(shù)據(jù)
  • 類組件 : 有狀態(tài) , 有自己的數(shù)據(jù)

狀態(tài) State 的簡單說明

state 的定義

  • 方式1 : constructor 里面
constructor() { super()//設(shè)置狀態(tài)1this.state = {name : 'zs'}}
  • 方法2 : 屬性初始化語法
// 設(shè)置狀態(tài)2 state = {name :'zhangsan '}

獲取 狀態(tài) 值 :

// 直接獲取<p> { this.state.name }</p>// 解構(gòu)獲取const { name } = this.state<p> { name }</p>

修改 狀態(tài) 值

// 鉤子函數(shù) - 組件掛載完全 render調(diào)用完后會調(diào)用 componentDidMount() {//1. 直接修改// 如果使用 this.state.name = '春春' , 這樣只會修改state里面的數(shù)據(jù),但是無法更新視圖// this.state.name = '春春'//2. 使用 setState 修改// 1-修改數(shù)據(jù) 2-重新調(diào)用render, 更新視圖this.setState({name: '春春'}) }

安裝 React 插件 ==> 查看 state 的值

  • react-developer-tools.crx
  • 安裝步驟 : 后綴crx 改為 zip, 解壓到當(dāng)前文件, 安裝 拓展程序

使用 state 修改定時(shí)器

//2. 類組件 class Child extends React.Component {state = {time : new Date() # + }render() {return (<div><h3>我是h3</h3><p>{ this.state.time.toLocaleTimeString() }</p> # + </div>)}componentDidMount () { setInterval(() => {this.setState({ # + time: new Date() # + }) # + }, 1000);} }

總結(jié) :

  • 函數(shù)組件
    • 沒有狀態(tài) ( 沒有自己的私有數(shù)據(jù) )
    • 木偶組件, 組件一旦寫好, 基本就不會改變
    • 傳參 : function Child( props ) { } , props 只讀
  • 類組件
    • 有狀態(tài) ( 有自己的私有數(shù)據(jù) state )
    • 智能組件, 狀態(tài)發(fā)生改變, 就會更新視圖
    • 傳參 :
      • this.props
  • 優(yōu)點(diǎn)
    • 類組件 : 有狀態(tài),有生命周期鉤子函數(shù), 功能比較強(qiáng)大
    • 函數(shù)組件 : 渲染更快
  • 以后區(qū)分使用 ?
    • 就看要不要狀態(tài) , 要狀態(tài)(類組件) , 不要狀態(tài) (函數(shù)組件)
  • props 和 state 區(qū)別?
    • state - 自己的私有數(shù)據(jù) 類似 vue 里的data
    • props - 外界傳進(jìn)來的 類似 vue 里面的props

事件處理

事件注冊

  • 以前注冊事件
<button onclick='fn'>按鈕</button>
  • react 中注冊事件
    • 注冊事件屬性采用的是駝峰的 onClick=…
    • 注冊事件的事件處理函數(shù) , 寫為函數(shù)形式,不能為字符串
    • onClick={ this.fn }, {} 可以拿到它的原始類型
// 注冊事件 <button onClick={ this.fn }>按鈕</button>// 事件處理函數(shù) fn() {console.log('我被點(diǎn)擊了') }

事件中 this 的處理

  • 演示this問題
// 注冊 <button onClick={this.fn}>按鈕</button> // 事件 fn () { console.log('點(diǎn)擊了');this.setState({name : 'ls'}) } // 報(bào)錯(cuò) : Uncaught TypeError: Cannot read property 'setState' of undefined // react 中的this=undefined 是需要處理的
  • bind 和 call 的回憶使用
function f() {console.log(this) }let obj = { name: 'zs' }bind 的使用 f.bind(obj) : f里面的this 指向了obj 綁定之后沒有打印,不是bind出了問題,而是bind和call,和apply() call和apply 1-調(diào)用 2-指向 bind 1-指向 2-返回一個(gè)新函數(shù) let newF = f.bind(obj)newF()
  • 方式1 : bind
- 第一種constructor() { super()this.fn1 = this.fn1.bind(this)}- 第二種 : <button onClick={ this.fn1.bind(this) }>按鈕</button>
  • 方式2 : 屬性初始化語法
// 注冊事件 return <button onClick={this.fn2}>按鈕</button> // 屬性初始化語法 fn2 = () => { // 箭頭函數(shù)里面的this指向了外部的thisthis.setState({name : 'ls'})}
  • 方式3 : 箭頭函數(shù)
<button onClick={ () => this.fn3() }>按鈕</button>// 箭頭函數(shù)里面的this 指向外部的this // 誰調(diào)當(dāng)前this所在的函數(shù), this就執(zhí)行誰 fn3(){... }
  • 總結(jié)
// 方法1 : bind (常用) return <button onClick={ this.fn.bind(this) }>按鈕</button> // 方法2 : 屬性初始化語法 return <button onClick={ this.fn1 }>按鈕</button> // 方法3 : 箭頭函數(shù) return <button onClick={ () => this.fn() }>按鈕</button>
  • 三者使用場景
- 方式1和方式3 常用 - 如果函數(shù)體內(nèi)的代碼比較少,比如就1~2=> 方式3 - 大部分情況下 => 優(yōu)先使用 方式2 - 如果涉及到傳參 => 方式3

點(diǎn)擊事件傳參 + 配合this處理

  • 演示效果
return <button onClick={this.fn(123)}>按鈕</button> 不能這樣傳參,因?yàn)檫€沒有開始點(diǎn)擊,就已經(jīng)開始調(diào)用了fn , 并且把參數(shù)傳過去了
  • 處理this方式1 : bind
// 注冊事 return <button onClick={ this.fn.bind(this,123) }>按鈕</button>// 傳參 fn( num ) { console.log('點(diǎn)擊了',num); }
  • 處理this方式2 : 屬性初始化語法 – 不能傳參
  • 處理this方式3 : 箭頭函數(shù)
// 注冊事 return <button onClick={ () => this.fn(123) }>按鈕</button>// 傳參 fn( num ) { console.log('點(diǎn)擊了',num); }

獲取事件對象 + 配合this處理

// 方式1 : bind , `處理函數(shù)最后一個(gè)參數(shù)`就是 事件對象 e return <button onClick={this.fn1.bind(this, 123, 456)}>按鈕</button> // 方式2 : 屬性初始化語法 不傳參數(shù) 默認(rèn)形參就是事件對象 e return <button onClick={this.fn2}>按鈕</button> // 方式3 : 箭頭函數(shù) 通過箭頭函數(shù)獲取e,再繼續(xù)傳 return <button onClick={e => this.fn3(e)}>按鈕</button> 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的React基础学习(第二天)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。