(React全解)Class組件詳解

一. class 組件創建方式

import React from 'react';

class B extends React.Component {
  constructor(props){
    super(props);
  }
  render(){
    return (
      <div>hi</div>
    )
  }
}

二. Props 外部數據

class Parent extends React.Component {
  constructor(props){
    super(props)
    this.state = {name:'frank'}
  }
  onClick = ()=>{}
  render(){
    return <B name={this.state.name} onClick={this.onClick}>hi</B>
  } // 這裏的name和onClick就是props,來源是從this.state來的,是從外部來的作爲props
}

// props如何初始化,這樣子做了之後this.props就是外部數據的對象地址了
class B extends React.Component {
  constructor(props){
    super(props);
  }
  render(){

  }
}

// 讀取props
class B extends React.Component {
  constructor(props){
    super(props);
  }
  render(){
    return <div onClick={this.props.onClick}>
      {this.props.name}
      <div>
        {this.props.children}
      </div>
    </div>
  }
}

// 不能去寫props,外部數據應該由外部更新

三. componentWillReceiveProps 的作用

  • 接收外部數據,只能讀不能寫,外部呀數據由父組件傳遞
  • 接受外部函數,在恰當的時機調用該函數,該函數一般是父組件的函數
import React from 'react';

class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {x : 1}
  }

  onClick = () => {
    this.setState({
      x: this.state.x + 1
    })
  }

  render(){
    return (
      <div className="App">
        App <button onClick={this.onClick}>+1</button>
        <B name={this.state.x}/>
      </div>
    );
  }
}

class B extends React.Component {
  UNSAFE_componentWillReceiveProps(newProps, nextContext) {
    console.log('舊的 props')
    console.log(this.props)
    console.log('props變化了')
    console.log('新的p props')
    console.log(newProps)
  }
  render(){
    return (
      <div>{this.props.name}</div>
    )
  }
}

export default App;

四. State & setState 內部數據

  • 初始化 State
class B extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      user: {name:'frank', age:187}
    }
  }
  render(){

  }
}
  • setState 的兩種方式,推薦寫成函數的形式,一般就用第一個參數,還有第二個參數接受成功之後的回調函數,另外寫 state 的時候會進行一級合併(shallow merge)
  onClick = () => {
    this.setState({
      x: this.state.x + 1
    })
    this.setState({
      x: this.state.x + 1
    })
  }

  onClick2 = () => {
    this.setState((state)=>({x:state.x+1}))
    this.setState((state)=>({x:state.x+1}))
  }

五. 生命週期

let div = document.createElement('div')
// 這是div的 create/construct 過程
div.textContent = 'hi'
// 這是初始化state
document.body.appendChild(div)
// 這是div的mount過程
div.textContent = 'hi2'
// 這是div的update過程
div.remove()
// 這是div的unmount過程
  • 函數列表,以下是常用的

    constructor() - 這裏初始化state
    shouldComponentUpdate() - return false 阻止更新
    render() - 創建虛擬DOM
    componentDidMount() - 組件已出現在頁面
    componentDidUpdate() - 組件已更新
    componentWillUnmount() - 組件將死
  • constructor的用途

    • 初始化props

    • 初始化state,但此時不能調用setState

    • 用來寫bind this

        constructor(){
            this.onClick = this.onClick.bind(this)
        }
        可以用新語法代替
        onClick = ()=> {}
        constructor() {
      
        }
    • 可不屑

  • shouldComponentUpdate的用途

    • 返回true表示不阻止UI更新
    • 返回false表示阻止UI更新
    • 示例見下頁
    • 面試常問: shouldComponentUpdate有什麼用?
    • 答: 它允許我們手動判斷是否要進行組件更新,我們可以根據應用場景靈活地設置返回值,以避免不必要的更新
  • React.PureComponent會對state和props進行淺對比,就不需要shouldComponentUpdate了

  • render的用途

    • 展示視圖,

      // return 對應的對象是不是一個dom元素, 而是一個表示dom元素的對象, 我們稱其虛擬dom 
      return (<div>...</div>)
    • 只能有一個根元素

      用React.Fragment做佔位,也可以寫成<></>,兩者等價
      • 技巧
        // render裏面可以寫if...else
        // 可以寫?:
        // 不能直接寫for,需要用數組
        // 可以寫array.map 
        

      import React from 'react';

      class App extends React.PureComponent { constructor(props){

      super(props)
      this.state = {
        n:1
      }

      } onClick= ()=>{

      this.setState(state=> ({
        n: state.n+1
      }))

      }

      render(){

      console.log('render了一次')
      let message
      if(this.state.n % 2 === 0 ) {
        message = <div>偶數</div>
      } else {
        message = <span>奇數</span>
      }
      return (
        <>
          {message}
          <button onClick={ this.onClick }>+1</button>
        </>
      )

      } }

      export default App; // 循環的寫法 render() { return this.state.array.map(n=>{n}) }

      - componentDidMount()的用途
        - 在元素插入頁面後執行代碼,這些代碼依賴DOM
        - 比如你想獲取div的高度,就最好在這裏寫
        - 此處可以發起加載數據的AJAX請求(官方推薦)
        - 首次渲染會執行此鉤子

      componentDidMount() { const div = document.getElementById('xxx') const {width} = div.getBoundingClientRect() // console.log(width) this.setState({width}) }

      render(){

      return(
        <div id='xxx'>Hello World, {this.state.width}
        </div>
      )

      } ```

      • 也可以用ref來做

        import React from 'react';
        
        class App extends React.PureComponent {
          constructor(props){
            super(props)
            this.state = {
              n:1,
              width: undefined
            }
            this.divRef = React.createRef()
          }
          onClick= ()=>{
            this.setState(state=> ({
              n: state.n+1
            }))
          }
        
          componentDidMount() {
            const div = this.divRef.current
            const {width} = div.getBoundingClientRect()
            // console.log(width)
            this.setState({width})
          }
        
          render(){
            return(
              <div ref={this.divRef}>Hello World, {this.state.width}px
              </div>
            )
          }
        }
        
        export default App;
        
    • componentDidUpdate()的作用

      • 在視圖更新後執行代碼
      • 此處也可以發起AJAX請求,用於更新數據(看文檔)
      • 首次渲染不會執行此鉤子
      • 在此處setState可能會引起無限循環,除非放在if裏
      • 若componentDidUpdate返回false,則不觸發此鉤子
      • componentWillUnmount的用途
      • 組件將要被移除頁面然後被銷燬時執行的代碼
      • unmount過的組件不會再次mount
      • 舉例:
        如果你在componentDidMount裏面監聽了window scroll
        那麼就要在componentWillUnmount的用途裏面取消監聽
        如果你在componentDidMount裏面創建了Timer
        那麼就要在componentWillUnmount裏面取消Timer
        如果你在componentDidMount裏面創建了AJAX請求,這種情況比較特殊,數據還沒回來你就死了 
        那麼就要在componentWillUnmount裏面取消請求
    • 總結:

      • 能用函數組件就用函數組件,能用purecomponent就用purecomponent,最後不行採用 react.component
      • 生命週期函數 生命週期.png

最後,個人微信,歡迎交流,提供工作機會。

wechat0.jpg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章