淺談react組件

組件化思想

vue和react都是現在最火的兩大前端框架之一,無論是vue,還是react,他們都採用的是組件化的思想。對於一個前端開發人員來說,組件這個詞並不陌生,也可以感受到組件所帶來的好處與快感。

我就隨性的講講我個人對組件化思想的看法,組件化並不是前端所特有的,在很多方面都會涉及到。我把它帶來的好處分類兩個大的方面:

  • 把複雜的問題進行拆分,簡化問題
  • 提高公共內容的複用性,靈活性

再通俗易懂的來說,就好比搭積木一樣,假如我們需要做一個火車模型,我們會在衆多的零散的積木零件中,找到所需要用到的零件,然後對他們進行合理的組合,最終拼成我們想要的東西。而不是你需要一個火車,樂高就直接給你做一個火車,你需要一個飛機,又重新給你做一個飛機,遇到一些難纏的甲方,當你給他做了一個飛機後,甲方爸爸覺得某個部位不滿意,你又要重新去做一個飛機。如果是使用零散的組件搭建的話,可以對某個局部進行方便快捷的調整。

有了組件化的思想還不夠,還要知道如何去劃分組件,不是說組件劃分的越小越好,在保證組件可以被靈活複用的前提下,減少無用的不必要的組件劃分。

vue組件與react組件

在vue中,一個.vue文件就爲一個組件,當然對於一個跟組件來說你也可以把它做爲一個頁面。

在react中,組件的形式更加的靈活,分爲函數式組件和class組件,在一個js或jsx文件中,我們可以創建任意多個組件。

每個組件從誕生到結束都會經歷一個生命週期,VUE中可分爲4大階段:創建、掛載、更新、銷燬,每個階段又可分成兩個週期,詳情如下:

  • beforeCreate:實例剛在內存中被創建出來,此時,還沒有初始化好 data 和 methods 屬性
  • created:data和methods已經創建完成,準備編譯模板
  • beforeMount:完成模板編譯,但未掛載到頁面中
  • mounted:將模板掛載對應的容器中
  • beforeUpdate:狀態更新之前執行此函數, 此時 data 中的狀態值是最新的,但是界面上顯示的 數據還是舊的,因爲此時還沒有開始重新渲染DOM節點
  • updated:實例更新完畢之後調用此函數,此時 data 中的狀態值 和 界面上顯示的數據,都已經完成了更新,界面已經被重新渲染
  • beforeDestroy:實例被銷燬之前調用,此時實例還可用
  • destroyed:Vue 實例銷燬後調用。調用後,Vue 實例指示的所有東西都會解綁定,所有的事件監聽器會被移除,所有的子實例也會被銷燬

react組件的生命週期可分爲3個狀態

  • Mounting:已插入真實 DOM

  • Updating:正在被重新渲染

  • Unmounting:已移出真實 DOM
    具有以下方法:

  • componentWillMount:在渲染前調用,在客戶端也在服務端。

  • componentDidMount:在第一次渲染後調用,只在客戶端。之後組件已經生成了對應的DOM結構,可以通過- this.getDOMNode()來進行訪問。如果你想和其他JavaScript框架一起使用,可以在這個方法中調用setTimeout, setInterval或者發送AJAX請求等操作(防止異步操作阻塞UI)。

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

  • shouldComponentUpdate:返回一個布爾值。在組件接收到新的props或者state時被調用。在初始化時或者使用forceUpdate時不被調用。
    可以在你確認不需要更新組件時使用。

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

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

  • componentWillUnmount:在組件從 DOM 中移除之前立刻被調用。

react組件

無論是哪種組件,他們的本質還是應該做一個組件應該做的事情。

一個組件可以分爲輸入、輸出、狀態三個部分

  • 輸入(props):父組件傳遞的內容
  • 輸出(render/return):返回所需要渲染的內容
  • 狀態(state):可以看做是充當輔助的角色,爲了達到所需要的結果所需要的一些必要的中間橋樑,簡單說,就是普通的數據

上面提到了react的組件有兩種形式,他們是不是沒有任何區別,或者說是在任何情況下都可以互換使用呢。

當然不是,我們通過一個例子來看看他們的不同。

class Component extends React.Component {
  constructor(props) {
  super(props)
  this.state = {
  value: 0,
      }
    }
    componentDidMount(){
      setInterval(() => {
  this.setState({
  value: this.state.value + 1
        })
      }, 1000);
    }
    render() {
  return <div>
  <div>
  <div>
  <h3>函數式組件</h3>
              {/*函數式組件*/}
  <h3>class組件</h3>
              {/*class組件*/}
  </div>
  </div>
  </div>
    }
}

上面有一個組件,這裏作爲父組件,父組件中有一個名爲value的狀態變量,在componentDidMount中有一個定時器,其作用是每隔1秒後,使value的值+1。

接下來我們就分別使用函數式和class的形式寫兩個子組件,他們具有相同的功能。

//函數式組件
function FunComponent(props){
  let {count} = props
  let handleClick = () => {
    setTimeout(() => {
      alert(count)
    }, 3000);
  }
​
  return (
    <div>
    <p>當前數量:{count}</p>
    <button onClick={handleClick}>Alert Count</button>
    </div>
    )
}
//class組件
class ClassComponent extends React.Component {
  constructor(props){
  super(props)
  this.state = {
      }
    }
    handleClick = () => {
      setTimeout(() => {
        alert(this.props.count)
      }, 3000);
    }
    render() {
  return <div>
  <p>當前數量:{this.props.count}</p>
  <button onClick={this.handleClick}>Alert Count</button>
  </div>
    }
 }

在子組件中,接收並顯示父組件傳遞的value值,並有一個按鈕,點擊按鈕3秒後彈出顯示value值。

在無任何操作的情況下,他們的值同步的變化,因爲他們都接收自同一個父組件所傳遞的值。

現在點擊第一個按鈕,3秒後彈出的count值與當前頁面中顯示的count值是不同的,而是等於點擊按鈕時的值。

點擊class組件中的按鈕,3秒後彈出的count值與當前頁面中顯示count值相同。
在這裏插入圖片描述

在某些情況下, 函數組件中的行爲才符合預期。如果將 setTimeout 類比到一次 Fetch 請求,在請求成功時,我要獲取的是發起 Fetch 請求前相關的數據,並對其進行修改。

爲什麼會產生這種差異?

在 class 組件中,我們是從 this 中獲取到的 props.count。this 是固定指向同一個組件實例的。在 3 秒的延時器生效後,組件重新進行了渲染,this.props 也發生了改變。當延時的回調函數執行時,讀取到的 this.props 是當前組件最新的屬性值。

而在 函數組件中,每一次執行 render 函數時,props 作爲該函數的參數傳入,它是函數作用域下的變量。這樣理解,在組件首次被創建時,就相當於調用了一次函數,當count值發生改變後,又一次調用了該函數,每一次調用之間都是相互獨立的,而props就是該函數的參數,每個函數在被調用時,它的參數就已經被確定,不會被其他函數所影響。

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