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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

react 学习(三) 组件更新

發布時間:2023/12/20 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 react 学习(三) 组件更新 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們上一節了了解了函數式組件和類組件的處理方式,本質就是處理基于 babel 處理后的 type 類型,最后還是要處理虛擬 dom。本小節我們學習下組件的更新機制。

我們知道我們定義類組件的時候,只能通過 setState 方式修改狀態值,這樣頁面才會重新渲染。如果你直接修改 state,其實沒有什么作用的。

實現簡版更新機制

我們先寫下 Counter 的例子,點擊加一,如下:

// src/index.jsclass Counter extends React.Component {constructor(props) {super(props);// 類的構造函數中 唯一給 state 賦值的地方this.state = {number: 0,};}handleClick = () => {// 明顯 setState 是繼承來的this.setState({number: ++this.state.number,});};render() {return (<div><p>{this.props.title}</p><p>{this.state.number}</p><button onClick={this.handleClick}>plus</button></div>);} } ReactDOM.render(<Counter title="加法" />, document.getElementById("root"));

實現 setState

// src/Component.js export class Component {constructor(props) {// react 的實例單獨注冊了一個更新器,回來統一處理 state,類似寫函數嵌套多了,把不同功能單獨提出去this.updater = new Updater(this) // 把組件實例傳入}setState(partialState) {// 我們可以寫多個 setState 方法,react 會統一處理,所以很明顯使用一個棧存儲的this.updater.addState(partialState)} }class Updater{constructor(classInstance) {this.classInstance = classInstancethis.pendingStates = []}addState(partialState) {// 狀態存儲this.pendingStates.push(partialState)// 觸發更新this.emitUpdate()}emitUpdate() {this.updaetComponent()}// 組件更新原理//1.計算新的 state//2.重新執行render//3.得到新的虛擬dom,真實dom//4.覆蓋重新掛載updaetComponent() {const {calssInstance, pendingStates} = thisif (pendingStates.length) {// 獲取新的狀態let newState = this.getState()// 查看是否更新showUpdate(classInstance, newState)}}getState() {const {classInstance, pendingStates} = this// 得到老狀態let {state} = classInstance// 合并狀態pendingStates.forEach(nextState => {state = {...state,...nextState}})// 清空pendingStates.length = []return state} }function showUpdate(classInstance, newState) {classInstace.state = newState // 用新的狀態 直接覆蓋組件實例的狀態classInstance.forceUpadte() // 強制更新, 此方法在父組件上 }

強制更新

// Components.js Component 類 // 這里的邏輯是 獲取老的真實dom,獲取新的虛擬dom 生成的真實dom,使用 replaceChild 方法,用新的dom替換舊的真實dom forceUpdate() {let oldRenderVdom = this.oldRenderVdomlet oldDOM = finDOM(oldRenderVdom) // 根據虛擬 dom 獲取真實domlet newRenderVdom = this.render()compareTowVdom(oldDOM.parentNode, oldDOM, newRenderVdom)this.oldRenderVdom = newRenderVdom }

這里可能有的朋友有疑問,舊的虛擬 dom,舊的真實 dom,那里獲取的呢,我們還的改動下上一小節的代碼:

// react-dom.jsfunction createDOM(vdom) {...vdom.dom = dom // 我們把得到的真實 dom,添加到虛擬 dom 對象上...}// 函數組件 babel 把屬性轉為 props 對像 function mountFunctionComponent(vdom) {const { type, props } = vdom;// 函數式組件 type 是個 函數 返回虛擬函數let renderVdom = type(props);// 把舊的 渲染的虛擬dom 存起來 / 看這里vdom.oldRenderVdom = renderVdom;return createDOM(renderVdom); }// 類組件 function mountClassComponent(vdom) {const { type, props } = vdom;const classInstance = new type(props);const renderVdom = classInstance.render();// 把舊的 渲染的虛擬dom 存儲 / 看這里classInstance.oldRenderVdom = vdom.oldRenderVdom = renderVdom;return createDOM(renderVdom); }

通過上面添加的代碼,我們已經在虛擬 dom 上和類的實例上綁定了虛擬 dom,所以回過頭來我們可以在 forceUpdate 方法中獲取舊的虛擬 dom,那如何拿到舊的真實 dom 呢?

// react-dom.js function findDOM(vdom) {if (!vdom) return nullif (vdom.dom) return vdom.dom // 我們在上面 createDOM 中做了綁定// 如果沒有虛擬domlet renderVdom = vdom.oldRenderVdomreturn findDOM(renderVdom) }

什么情況下會沒有虛擬 dom 呢?例如 function One() {return <h1>123<h1/>}, function Two() {return <One />},我們調用 Two 函數的時候,得到的就不是虛擬 dom,這個時候就需要繼續遞歸 findDOM。

實現 compareTwoVdom 進行 dom 替換

// react-dom.js function compareTwoVdom(parentDOM, oldDOM, newVdom) {let newDOM = createDOM(newVdom) // 我們執行 render 得到的新的虛擬 domparentDOM.replace(newDOM, oldDOM) // 完成替換 }

這里遺漏了一個小問題,我們沒有處理點擊事件,我們需要在屬性中判斷是否是 on 開頭的變量:

// react-dom.js function updateProps() {....if (/^on[A-Z].*/.test(key)) {// 轉成 js 原生的小寫dom[key.toLowerCase()] = newProps[key]}... }

我們在入口文件中改用我們自己寫的代碼,發現效果一樣。當讓這里這是簡單的實現完全的 dom 替換,沒有對 setState 做異步處理,但是我們已經能理解 react 類組件的更新原理。

我們下一小節實現批量更新和合成事件,如果有不對,歡迎指正!

總結

以上是生活随笔為你收集整理的react 学习(三) 组件更新的全部內容,希望文章能夠幫你解決所遇到的問題。

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