<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # Counter計數器組件 通過計數器組件來實現數字增加和減少。 ## 涉及知識點 >綁定事件,this指向解決,生命周期。內容量還是比較多的 ## 新建Counter組件 `src/components/Counter.js` ~~~jsx import React, {Component} from 'react' export default class Counter extends Component { constructor(props) { super(props) this.state = {num: 0} } icrement() { this.setState({ num: this.state.num + 1 }) } render() { return <div> <span id="span">{this.state.num}</span> <br/> <button onClick={this.icrement.bind(this)}>增加</button> </div> } } ~~~ # 問題 1.在這里面要注意數據更新必須是通過**this.setState()**來進行更新數據, 不可以直接對數據進行this.state.num++這種前置++或者后置++來實現效果。因為this.state.num++只會影響數據增加,但不會更新視圖。 this.setState()其實和微信小程序的操作方式很相似。 2.綁定事件,綁定事件要注意,這里要通過onClick= {this.increment}這樣寫會報錯,this指向有問題。打印后this是undefined。必須手動修改this指向。通過this.increment.bind(this); 為什么不是call 和applay,而是bind。答案很簡單,call和applay調用的話會立即執行。而bind 不會立即執行它是call和applay的衍生版。 下面是bind的簡易版實現方式。 ~~~ function bind(fn,context){ return function(){ return fn.apply(context,arguments) } } ~~~ 如果想看復雜版請查看[Bind高級版](https://www.jianshu.com/p/4b293581a03f) # 正式進入生命周期 ## 初始化階段 ### `constructor`初始化數據 ~~~ console.log('這是constructor') console.log(document.getElementById('box')) this.setState({ num:1 }) ~~~ 打印結果 ``` 這是constructor null ``` 通過打印結果說明網頁初始化發布時,默認會先執行constructor生命周期,在這時候還不能獲取到真實的dom元素。 ### `componentWillMount`將要被掛載 ~~~ componentWillMount() { console.log('這是componentWillMount',2) console.log(document.getElementById('box')) } ~~~ 打印結果 ``` 這是componentWillMount 2 null ``` 通過打印結果說明網頁初始化發布時,第二個執行componentWillMount生命周期,這時候還不能獲取到真實的dom元素。 ### render生命周期 進行渲染 因為初始化,它會先將數據和結構進行綁定,然后轉換為虛擬dom,此時不需要domdiff算法,直接將數據呈現在網頁中即可。 ~~~jsx render() { console.log('這是render',3) console.log(document.getElementById('box')) return <div id="box"> <span id="span">{this.state.num}</span> <br/> <button onClick={this.icrement}>增加</button> </div> } ~~~ 打印結果 ``` 這是render 3 null ``` 通過打印結果說明網頁初始化發布時,第三個執行render 生命周期,這時候還不能獲取到真實的dom元素。 ### `componentDidMount`掛載完成 ~~~ componentDidMount() { console.log('這是componentDidMount',4) console.log(document.getElementById('box')) } ~~~ ``` 這是componentDidMount 4 <div id=?"box">?…?</div>? ``` 通過打印結果說明,網頁初始化發布是,第四個執行componentDidMount 生命周期,這時候數據和模板已經更新完成,可以獲取真正的元素了。 #初始化生命周期小結 通過上面我們已經可以得到什么時候可以去獲取真實的dom元素以及它們的執行順序。 # 運行中生命周期 運行中生命周期分兩種情況,可以根據下圖來說明,第一種是私有數據發生改變,第二種是屬性發生改變。 ![](https://box.kancloud.cn/1c14d8a7a85b626eccf1994765579a5b_1611x909.png) # 我們先研究私有數據即state發生改變的情況。 ## shouldComponentUpdate 組件是否更新生命周期 ~~~ shouldComponentUpdate(nextProps, nextState, nextContext) { console.log('shouldComponentUpdate',5) console.log(document.getElementById('box').innerHTML) } ~~~ 單擊增加按鈕,我們讓state中的num值變為10,控制臺會輸出下面內容。 ``` shouldComponentUpdate 5 <span id="span">0</span><br><button>增加</button> Warning: Counter.shouldComponentUpdate(): Returned undefined instead of a boolean value. Make sure to return true or false. ``` 控制臺輸出說明,它默認不會自動觸發,當私有數據發生變化時才會更新,同樣的也能獲取到標簽元素,不過注意這個標簽元素是老的數據,并不是最新的。 我們也發現瀏覽器中并未將數據更新為10。控制臺還報錯了:我們必須在這個生命周期中返回true或者false。返回true表示會更新,如果返回false則不更新。 可以嘗試自己寫寫試試效果 ### 小結 `shouldComponentUpdate`生命周期,一般我們可以用來優化性能,需要人為來處理,一般對于基礎數據我們可以來進行性能優化,如果是比較復雜的對象或者數組則不需要,讓它在`render`中進行優化。 ## componentWillUpdate ~~~ componentWillUpdate(nextProps, nextState, nextContext) { console.log('componentWillUpdate',6) console.log(document.getElementById('box').innerHTML) } ~~~ 控制臺輸出 ``` componentWillUpdate 6 <span id="span">0</span><br><button>增加</button> ``` 根據控制臺輸出結果我們可以看到組件將要被更新,且能獲取到元素,且元素的內容還是老舊內容。 ## render生命周期函數 render生命周期函數改造 在此時,這個生命周期函數做的事情較為復雜,內部需要對比老舊的虛擬dom,進行diff算法。 ~~~ console.log('這是render',3) console.log(document.getElementById('box')&&document.getElementById('box').innerHTML) ~~~ 控制臺輸出 ``` 這是render 3 Counter.js:65 <span id="span">0</span><br><button>增加</button> ``` 根據控制臺輸出,表明render生命周期還是之前那一個,同樣的,它獲取的元素內容還是之前老舊的內容。 ## componentDidUpdate生命周期 ~~~ componentDidUpdate(prevProps, prevState, snapshot) { console.log('componentDidUpdate',7) console.log(document.getElementById('box').innerHTML) } ~~~ 控制臺輸出 ``` componentDidUpdate 7 <span id="span">1</span><br><button>增加</button> ``` 這時我們它是運行中生命周期中最后一個,同時,完成更新后,它獲取的元素內容已經成為最新的了。 ## 運行中生命周期小結 運行中生命周期中是組件持續時間最長的。只要觸發this.setState這個函數它就會執行。 大家可以猜想一下為什么在初始化render生命周期不可以調用this.setState可以直接告訴大家它是死循環,可以將你的思考總結一下(了解一下)**,這個題需要看完思考題 再來解釋。** # 組件銷毀生命周期(了解掌握) 組件銷毀生命周期這個案例比較復雜,在理解上有點麻煩。大家剛開始時候只需要能跟著寫就可以了。在這里我們需要再學習兩個ReactDOM的api。 通過ReactDOM的unmountComponentAtNode來卸載組件。不過這里卸載組件只能卸載通過ReactDOM.render加載的組件。 ~~~ ReactDom.unmountComponentAtNode(document.getElementById('box')) 銷毀指定容器內的所有React節點。 ~~~ 我們需要結合Counter計數組器組件和Main.js中添加一層組件Life組件。 ## 新建Life.js組件 ~~~ import React, {Component, Fragment} from 'react' import ReactDom from 'react-dom' import Counter from "./Counter"; export default class Life extends Component{ unmont(){ ReactDom.unmountComponentAtNode(document.getElementById('mybox')) } render() { return ( <Fragment> <button onClick={this.unmont.bind(this)}>卸載</button> <div id="mybox"> <Counter/> </div> </Fragment> ) } } ~~~ ### 修改main.js ~~~ ReactDom.render(<Life/>,document.getElementById('root')) ~~~ ![](https://box.kancloud.cn/d8350225367478bda6a33091e05703ec_521x97.png) ##嘗試卸載 單擊卸載按鈕報錯 ``` Warning: unmountComponentAtNode(): The node you're attempting to unmount was rendered by React and is not a top-level container. You may have accidentally passed in a React root node instead of its container. ``` 報錯信息,說的不通過這種形式卸載組件。 ## 解決問題 我們還記得可以卸載的組件只能通過通過ReactDOM.render()的組件才可以卸載掉。 ~~~ unmont(){ ReactDom.unmountComponentAtNode(document.getElementById('mybox')) } mount(){ ReactDom.render(<Counter/>,document.getElementById('mybox')) } render() { return ( <Fragment> <button onClick={this.mount.bind(this)}>加載</button> <button onClick={this.unmont.bind(this)}>卸載</button> <div id="mybox"> </div> </Fragment> ) } ~~~ 通過上面,我們要通過單擊加載按鈕才可以讓元素顯示出來,同樣的我們單擊卸載,它也可以直接將Counter組件卸載掉。 我們設置Counter.js組件中的卸載生命周期 ~~~ componentWillUnmount() { console.log('componentWillUnmount',8); console.log(document.getElementById('box').innerHTML) } ~~~ 單擊卸載按鈕,控制臺輸出 ``` componentWillUnmount 8 Counter.js:111 <span id="span">0</span><br><button>增加</button> ``` 組件卸載生命周期只有一個,但是也比較重要,比如當前頁面被卸載掉后我們經常要使用它來清除定時器,以達到節省性能的效果。 # 運行中生命周期第二種情況 運行中生命周期第二種情況就是當父組件給子組件傳遞數據,引發的改變。 那么LIfe組件中使用了Counter組件,那么在Life組件中我們可以去改變Counter組件的數據。 ## Life組件 ~~~ import React, {Component, Fragment} from 'react' import ReactDom from 'react-dom' import Counter from "./Counter"; export default class Life extends Component{ constructor(props){ super(props); this.state = { number:10 } } unmont(){ ReactDom.unmountComponentAtNode(document.getElementById('mybox')) } mount(){ ReactDom.render(<Counter number={this.state.number}/>,document.getElementById('mybox')) } changeState(){ this.setState({ number:100 },()=>{ this.mount(); }) } render() { return ( <Fragment> <button onClick={this.changeState.bind(this)}>修改number</button> <button onClick={this.mount.bind(this)}>加載</button> <button onClick={this.unmont.bind(this)}>卸載</button> <div id="mybox"> </div> </Fragment> ) } } ~~~ ## Countr組件 ~~~ constructor(props) { super(props) this.state = {num: props.number} console.log('這是constructor,1') console.log(document.getElementById('box')) } componentWillReceiveProps(nextProps, nextContext) { console.log('componentWillReceiveProps',9) console.log(document.getElementById('box').innerHTML) } ~~~ ## 解釋 在這里面我們在Life組件中新添加了私有數據,然后級Counter組件的父組件傳遞number數據,讓子組件接收props,然后將props的數據放到Counter組件的state數據的num屬性中 ### 單擊加載,再單擊修改number 控制臺輸出結果 ``` componentWillReceiveProps 9 <span id="span">10</span><br><button>增加</button> shouldComponentUpdate 5 <span id="span">10</span><br><button>增加</button> componentWillUpdate 6 <span id="span">10</span><br><button>增加</button> 這是render 3 <span id="span">10</span><br><button>增加</button> componentDidUpdate 7 <span id="span">10</span><br><button>增加</button> ``` 我們可以看出只要當父組件的屬性的值發生變化 ,那么會引起子組件運行中的所有生命周期會一一執行。不過還可以發現一個問題,我們更新父組件中的number值,子組件并沒有更新成功,原因是因為什么呢? ### 解決 componentWillReceiveProps 這個生命周期我們可以接收到父容器的數據,我們來查看一下。 其實我們應該利用最新的屬性數據來改變私有數據。讓其更新。基本新的私有數據如何獲得呢?我們通過控制臺發現props并不是最新的數據,而nextProps才是最新的數據 ~~~ componentWillReceiveProps(nextProps, nextContext) { console.log(this.props.number) console.log(nextProps.number) console.log('componentWillReceiveProps',9) console.log(document.getElementById('box').innerHTML) } ~~~ ![](https://box.kancloud.cn/837b6c50ddab4a255d6f4c0318153ab2_1215x337.png) 和最新的props數據來更新state中的數據 ~~~ componentWillReceiveProps(nextProps, nextContext) { console.log(this.props.number) console.log(nextProps.number) this.setState({ num:nextProps.number }) console.log('componentWillReceiveProps',9) console.log(document.getElementById('box').innerHTML) } ~~~ ![](https://box.kancloud.cn/3e97cf36be81b57489ee8ccf91039cc4_1027x314.png) ## 思考題: 但是他們什么時候可以去更新數據呢?也就是this.setState這個函數在生命周期中什么時候可以執行呢?即比如ajax呢? 我們可以在上面的所有生命周期中,都添加`this.setState({num:10})`。 發現如下效果: ### constructor中不能更新數據 ~~~ Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the Counter component ~~~ >警告:無法對尚未掛載的組件調用SetState。這是一個禁止操作,但它可能指示應用程序中的錯誤。相反,直接分配給“this.state”,或在計數器組件中定義一個具有所需狀態的“state=”類屬性。 ### render,shouldComponentUpdate,componentWillUpdate,componentDidUpdate不能更新數據錯誤原因一樣 ~~~ Uncaught Invariant Violation: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops. ~~~ 超出最大更新深度。當組件在componentWillUpdate或componentDidUpdate中重復調用setState時,可能會發生這種情況。React限制嵌套更新的數量以防止無限循環。 原因是為什么?因為當state發生改變會執行上面的生命周期,自然而然的就導致死循環,最終報錯。 ### componentWillMount,componentDidMount,componentWillReceiveProps可以更新數據 這里面可以進行ajax。 ![](https://box.kancloud.cn/a60c788caa3764ca3cf4ef131068743a_898x518.png) 總結:React生命周期在學習上成本上是很大的,在剛工始學習過程中會遇到問題,也會感覺到特別麻煩 ,反而沒有Vue的生命周期好用。這些都是正常的,要多練習幾次就可以達到熟練的效果。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看