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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

React基础学习(第二天)

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

虛擬DOM

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

定時器渲染問題

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

渲染模式 :

/*** 最早的更新模式* 1. 數據* 2. 模板* 3. 數據+模板 => 真實的DOM* 4. 數據變了 => 最簡單直接的方式 => 最新數據+模板 => 新的DOM* 5. 新的DOM 把 舊的DOM完全直接替換掉* 6. 顯示新的DOM** 缺點 : 完全替換, 性能不好** 1. 數據* 2. 模板* 3. 數據+模板 => 真實的DOM* 4. 數據變化了 => 最新的數據 + 模板 => 新的DOM* 5. 新的DOM 和 舊的DOM 進行一一比較, 找到需要更新的地方* 6. 只需要更新需要改變的地方即可** 優點 : 不再是全部替換掉,* 缺點 : DOM比較就有性能問題了 , 會有多余的DOM和屬性進行比較(打印一級屬性),有損性能* p 和 p對比 h3 和h3對比(多余的對比)** 1. 數據* 2. 模板* 3. 數據 + 模板 => 虛擬DOM (js對象) => 真實的DOM* 4. 數據發生改變(zs=>ls) => 最新的數據 + 模板 => 新的虛擬DOM* 5. 新的虛擬DOM 和 舊的虛擬DOM 通過 diff算法 進行比較* 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 算法。包括幾個步驟:- 1.用 JavaScript 對象結構表示 DOM 樹的結構;然后用這個樹構建一個真正的 DOM 樹,插到文檔當中 - 2.當狀態變更的時候,重新構造一棵新的對象樹。然后用新的樹和舊的樹進行比較,記錄兩棵樹差異 - 3.2 所記錄的差異應用到步驟 1 所構建的真正的 DOM 樹上,視圖就更新了

DIff 算法

React 中有兩種假定:

  • 1 兩個不同類型的元素會產生不同的樹
  • 2 開發者可以通過 key 屬性指定不同樹中沒有發生改變的子元素

Diff 算法的說明 - 1

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

Diff 算法的說明 - 2

  • 對于類型相同的 React DOM 元素,React 會對比兩者的屬性是否相同,只更新不同的屬性
  • 當處理完這個 DOM 節點,React 就會遞歸處理子節點。
// 舊 <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 當在子節點的后面添加一個節點,這時候兩棵樹的轉化工作執行的很好
// 舊 <ul><li>1</li><li>2</li> </ul>// 新 <ul><li>1</li><li>2</li><li>3</li> </ul>執行過程: React會匹配新舊兩個<li>1</li>,匹配兩個<li>2</li>,然后添加 <li>3</li> tree
  • 2 但是如果你在開始位置插入一個元素,那么問題就來了:
// 舊 <ul><li>1</li><li>2</li> </ul>// 新 <ul><li>3</li> li3 插入最前面<li>1</li><li>2</li> </ul>執行過程: React將改變每一個子節點,而非保持 <li>1</li><li>2</li> 不變

key 屬性

為了解決以上問題,React 提供了一個 key 屬性。當子節點帶有 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>執行過程:現在 React 知道帶有key '3' 的元素是新的,對于 '1''2' 僅僅移動位置即可

補充說明:

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

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

  • 注意:key 只需要保持與他的兄弟節點唯一即可,不需要全局唯一

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

組件

組件1 - 函數組件

基本使用

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

傳參

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

箭頭函數改造

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

組件2 - 類組件

基本使用

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

傳參

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

ES6 - class

介紹

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

使用 class 創建對象

  • 使用class 創建一個類 class Person { }
  • 創建對象 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 繼承* 當前類里面的 constructor 里面一定要加上super()* 因為底層都是給我們加的super,所以我們才能夠繼承過來,* 如果我們直接寫 constructor,而不寫super,意外著,底層的constructor會被覆蓋掉*/ // 中國人 class Chinese extends Person {constructor() {super() // super 其實就是調用父類的constructorthis.name = 'zs'} }let c = new Chinese() console.log(c)

函數組件和類組件的小結

  • 函數組件 : 函數創建組件
    • 函數名首字母一定要大寫
    • 把組件當成標簽使用
    • 函數內部 通過 return jsx
  • 類組件 : 類創建組件
    • 首字母也要大寫
    • 一定要繼承(extends) React.Component
    • 類里面一定要有一個 render 函數
    • render 函數里面通過 return jsx
    • 類組件也是當成標簽一樣使用的

函數組件和類組件的區別?

  • 函數組件 : 沒有狀態的, 沒有自己的數據
  • 類組件 : 有狀態 , 有自己的數據

狀態 State 的簡單說明

state 的定義

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

獲取 狀態 值 :

// 直接獲取<p> { this.state.name }</p>// 解構獲取const { name } = this.state<p> { name }</p>

修改 狀態 值

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

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

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

使用 state 修改定時器

//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);} }

總結 :

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

事件處理

事件注冊

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

事件中 this 的處理

  • 演示this問題
// 注冊 <button onClick={this.fn}>按鈕</button> // 事件 fn () { console.log('點擊了');this.setState({name : 'ls'}) } // 報錯 : 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-調用 2-指向 bind 1-指向 2-返回一個新函數 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 = () => { // 箭頭函數里面的this指向了外部的thisthis.setState({name : 'ls'})}
  • 方式3 : 箭頭函數
<button onClick={ () => this.fn3() }>按鈕</button>// 箭頭函數里面的this 指向外部的this // 誰調當前this所在的函數, this就執行誰 fn3(){... }
  • 總結
// 方法1 : bind (常用) return <button onClick={ this.fn.bind(this) }>按鈕</button> // 方法2 : 屬性初始化語法 return <button onClick={ this.fn1 }>按鈕</button> // 方法3 : 箭頭函數 return <button onClick={ () => this.fn() }>按鈕</button>
  • 三者使用場景
- 方式1和方式3 常用 - 如果函數體內的代碼比較少,比如就1~2=> 方式3 - 大部分情況下 => 優先使用 方式2 - 如果涉及到傳參 => 方式3

點擊事件傳參 + 配合this處理

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

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

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

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。