react學習(6)——關於組件生命週期的問題

來源:互聯網
上載者:User

在項目開發的過程中,遇到了一個問題:

父組件請求後台資料,收到後將資料以props傳給子組件,子組件根據收到資料的不同,顯示不同的內容,同時,子組件自身可以根據click操作改變根據父組件的資料顯示的內容。

因此,子組件收到父組件的props傳值後,由於props值不能修改,因此子組件需要將該props值放入state,子組件根據自身click操作改變state,進而改變組件顯示的內容。

而父組件傳過來的值,子組件在componentDidMount中無法擷取,可以在render中擷取。但是若將擷取值的部分寫在render中,會導致頁面每次更新都從父組件拿值,子組件的click操作修改值無法起作用。

子組件代碼如下:

class child extends PureComponent {    static propTypes = {        value: PropTypes.bool.isRequired    };    constructor(props) {        super( props);        this.state = {            value: false        };    }    changeValue = () => {        this.setState({            value: false        });    }    render() {        this.state = {            value: this.props.value        };        return (            <div  style={{ display: value ? 'block':'none' }}>               <img src={src} alt="" />               <div className={styles.value}>這是父組件的傳值:{value}</div>               <div className={styles['icon-close']} onClick={this.changeValue}>                   <img src={close} alt="" />               </div>            </div>        );    }}export default Child;

 

解決方案1:將click的close方法寫在render中

但該寫法不是很規範,render() 函數應該是純粹的,也就是說該函數不修改組件state,每次調用都返回相同的結果,不讀寫 DOM 資訊,也不和瀏覽器互動(例如通過使用 setTimeout)。

class child extends PureComponent {    static propTypes = {        value: PropTypes.bool.isRequired    };    constructor(props) {        super( props);        this.state = {            value: false        };    }    render() {        this.state = {            value: this.props.value        };        changeValue = () => {            this.setState({                value: false            });        }        return (            <div  style={{ display: value ? 'block':'none' }}>               <img src={src} alt="" />               <div className={styles.value}>這是父組件的傳值:{value}</div>               <div className={styles['icon-close']} onClick={changeValue}>                   <img src={close} alt="" />               </div>            </div>        );    }}export default Child;
解決方案2:使用componentWillReceiveProps
class child extends PureComponent {    static propTypes = {        value: PropTypes.bool.isRequired    };    constructor(props) {        super( props);        this.state = {            value: false        };    }    componentWillReceiveProps(nextProps) {        this.setState({            value: nextProps.value        });    }    changeValue = () => {        this.setState({            value: false        });    }    render() {        return (            <div  style={{ display: value ? 'block':'none' }}>               <img src={src} alt="" />               <div className={styles.value}>這是父組件的傳值:{value}</div>               <div className={styles['icon-close']} onClick={this.changeValue}>                   <img src={close} alt="" />               </div>            </div>        );    }}export default Child;
總結:react組件的生命週期
  • componentWillMount 
  • componentDidMount 
  • componentWillReceiveProps 
  • shouldComponentUpdate 
  • componentWillUpdate
  • componentDidUpdate 
  • componentWillUnmount
1.  componentWillMount 組件將要掛載

組件剛經曆constructor,初始完資料

在初始化渲染執行之前立刻調用,伺服器端和用戶端都只調用一次

組件還未進入render,組件還未渲染完成,dom還未渲染

如果在這個方法內調用setState,render() 將會感知到更新後的state,將會執行僅一次,儘管 state 改變了。

 2. componentDidMount 組件渲染完成

在初始化渲染執行之後立刻調用一次,僅用戶端有效(伺服器端不會調用)

此時dom節點已經產生,可以在這裡調用ajax請求,返回資料setState後組件會重新渲染

在生命週期中的這個時間點,組件擁有一個DOM 展現,你可以通過 this.getDOMNode() 來擷取相應 DOM 節點

可以在這個方法中調用setTimeout, setInterval或者發送AJAX請求等操作(防止非同步作業阻塞UI)

3.componentWillReceiveProps (nextProps)

在組件接收到一個新的 prop (更新後)時被調用。這個方法在初始化render時不會被調用。

在接受父組件改變後的props需要重新渲染組件時用到的比較多

用此函數可以作為react 在 prop 傳入之後, render() 渲染之前更新 state 的機會。

在該函數中調用 this.setState() 將不會引起第二次渲染。

通過對比nextProps和this.props,將nextProps setState為當前組件的state,從而重新渲染組件

componentWillReceiveProps (nextProps) {    nextProps.openNotice !== this.props.openNotice && this.setState({        openNotice:nextProps.openNotice    },() => {      console.log(this.state.openNotice:nextProps) //將state更新為nextProps,在setState的第二個參數(回調)可以列印出新的state  })}
4. shouldComponentUpdate(nextProps,nextState)

唯一用於控制組件重新渲染的生命週期

由於在react中,setState以後,state發生變化,組件會進入重新渲染的流程(暫時這麼理解,其實setState以後有些情況並不會重新渲染,比如數組引用不變)。react父組件的重新渲染會導致其所有子組件的重新渲染,這個時候其實我們是不需要所有子組件都跟著重新渲染的,因此需要在子組件的該生命週期中做判斷。在這裡return false可以阻止組件的更新

如果 shouldComponentUpdate 返回false,則 render() 將不會執行,直到下一次 state 改變。(另外,componentWillUpdate 和 componentDidUpdate 也不會被調用。)

在接收到新的props 或者 state,將要渲染之前調用。該方法在初始化渲染的時候不會調用,在使用 forceUpdate 方法的時候也不會。

預設情況下,shouldComponentUpdate 總會返回true,在 state 改變的時候避免細微的bug,但是如果總是小心地把 state 當做不可變的,在 render() 中只從 props 和state 讀取值,此時你可以覆蓋 shouldComponentUpdate 方法,實現新老 props 和state 的比對邏輯。

如果效能是個瓶頸,尤其是有幾十個甚至上百個組件的時候,使用 shouldComponentUpdate可以提升應用的效能。

5. componentWillUpdate (nextProps,nextState)

在組件接收到新的props或者state但還沒有render時被調用。在初始化時不會被調用。

shouldComponentUpdate返回true以後,組件進入重新渲染的流程,進入componentWillUpdate,這裡同樣可以拿到nextProps和nextState

你不能在該方法中使用this.setState()。如果需要更新state來響應某個prop的改變,可使用componentWillReceiveProps。

6. componentDidUpdate(prevProps,prevState)

在組件完成更新後立即調用。在初始化時不會被調用。

組件更新完畢後,react只會在第一次初始化成功會進入componentDidmount,之後每次重新渲染後都會進入這個生命週期

在組件的更新已經同步到DOM 中之後立刻被調用。

這裡可以拿到prevProps和prevState,即更新前的props和state。

使用該方法可以在組件更新之後操作DOM 元素。

為了相容 v0.9,DOM節點會作為最後一個參數傳入。如果使用這個方法,你仍然可以使用 this.getDOMNode() 來訪問 DOM 節點。

7.componentWillUnmount()

在組件從DOM 中移除的時候立刻被調用。

在該方法中執行任何必要的清理,比如無效的定時器,或者清除在 componentDidMount 中建立的 DOM 元素,移除所有組建中的監聽 removeEventListener

除此之外,8.constructor

constructor參數接受兩個參數props,context,可以擷取到父組件傳下來的的props,context,

如果你想在constructor建構函式內部使用props或context,則需要傳入,並傳入super對象。

只要組件存在constructor,就必要要寫super,否則this指向會錯誤9. render函數

render函數會插入jsx產生的dom結構,react會產生一份虛擬dom樹,

在每一次組件更新時,在此react會通過其diff演算法比較更新前後的新舊DOM樹,比較以後,找到最小的有差異的DOM節點,並重新渲染

react16中 render函數允許返回一個數組,單個字串等,不在只限制為一個頂級DOM節點,可以減少很多不必要的div

組件生命週期的執行順序:

在react的組件掛載及render過程中,最底層的子組件是最先完成掛載及更新的。

constructor()建構函式、componentWillMount執行順序:頂層父組件 ->子組件 ->子組件 ->底層子組件

render、componentDidMount順序:底層子組件 ->子組件 ->子組件 ->頂層父組件

以下是http://www.runoob.com菜鳥教程上面的一個執行個體:

class Button extends React.Component {  constructor(props) {      super(props);      this.state = {data: 0};      this.setNewNumber = this.setNewNumber.bind(this);  }    setNewNumber() {    this.setState({data: this.state.data + 1})  }  render() {      return (         <div>            <button onClick = {this.setNewNumber}>INCREMENT</button>            <Content myNumber = {this.state.data}></Content>         </div>      );    }}  class Content extends React.Component {  componentWillMount() {      console.log('Component WILL MOUNT!')  }  componentDidMount() {       console.log('Component DID MOUNT!')  }  componentWillReceiveProps(newProps) {        console.log('Component WILL RECEIVE PROPS!')  }  shouldComponentUpdate(newProps, newState) {        return true;  }  componentWillUpdate(nextProps, nextState) {        console.log('Component WILL UPDATE!');  }  componentDidUpdate(prevProps, prevState) {        console.log('Component DID UPDATE!')  }  componentWillUnmount() {         console.log('Component WILL UNMOUNT!')  }     render() {      return (        <div>          <h3>{this.props.myNumber}</h3>        </div>      );    }}ReactDOM.render(   <div>      <Button />   </div>,  document.getElementById('example'));

運行結果:

(控制台info)

點擊按鈕:

參考:www.jianshu.com/p/c9bc994933d5

          www.jianshu.com/p/ee122bb5b14b

          http://www.runoob.com/react/react-component-life-cycle.html

          50942808

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.