React 深刻系列2:組件分類

React 深刻系列,深刻講解了React中的重點概念、特性和模式等,旨在幫助你們加深對React的理解,以及在項目中更加靈活地使用React。

React 組件有不少種分類方式,常見的分類方式有函數組件和類組件,無狀態組件和有狀態組件,展現型組件和容器型組件。好吧,這又是一篇咬文嚼字的文章。可是,真正把這幾組概念咬清楚、嚼明白後,對於頁面的組件劃分、組件之間的解耦是大有裨益的。html

函數組件和類組件

函數組件(Functional Component )和類組件(Class Component),劃分依據是根據組件的定義方式。函數組件使用函數定義組件,類組件使用ES6 class定義組件。下面是函數組件和類組件的簡單示例:json

// 函數組件
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// 類組件
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

上面的兩種寫法是等價的,但函數組件的寫法要比類組件簡潔,不過類組件比函數組件功能更增強大。類組件能夠維護自身的狀態變量,即組件的state,類組件還有不一樣的生命週期方法,可讓開發者可以在組件的不一樣階段(掛載、更新、卸載),對組件作更多的控制。api

類組件有這麼多優勢,是否是咱們在開發中應該首選使用類組件呢?其實否則。函數組件更加專一和單一,承擔的職責也更加清晰,它只是一個返回React 元素的函數,只關注對應UI的展示。函數組件接收外部傳入的props,返回對應UI的DOM描述,僅此而已。固然,如上面例子所示,使用只包含一個render方法的類組件,能夠實現和函數組件相同的效果。但函數組件的使用能夠從思想上迫使你在設計組件時多作思考,更加關注邏輯和顯示的分離,設計出更加合理的頁面上組件樹的結構。實際操做上,當一個組件不須要管理自身狀態時,能夠把它設計成函數組件,當你有足夠的理由發現它須要「升級」爲類組件時,再把它改造爲類組件。由於函數組件「升級」爲類組件是有必定成本的,這樣就會要求你作這個改造前更認真地思考其合理性,而不是僅僅爲了一時的方便就使用類組件。數組

無狀態組件和有狀態組件

無狀態組件(Stateless Component )和有狀態組件(Stateful Component),劃分依據是根據組件內部是否維護state。無狀態組件內部不使用state,只根據外部組件傳入的props返回待渲染的React 元素。有狀態組件內部使用state,維護自身狀態的變化,有狀態組件根據外部組件傳入的props和自身的state,共同決定最終返回的React 元素。less

很容易知道,函數組件必定是無狀態組件,類組件則既能夠充當無狀態組件,也能夠充當有狀態組件。但如上文所述,當一個組件不須要管理自身狀態時,也就是無狀態組件,應該優先設計爲函數組件。函數

展現型組件和容器型組件

展現型組件(Presentational Component)和容器型組件(Container Component),劃分依據是根據組件的職責。fetch

展現型組件的職責是:組件UI長成什麼樣。展現型組件不關心組件使用的數據是如何獲取的,以及組件數據應該如何修改,它只須要知道有了這些數據後,組件UI是什麼樣子的便可。外部組件經過props傳遞給展現型組件所需的數據和修改這些數據的回調函數,展現型組件只是它們的使用者。展現型組件通常是無狀態組件,不須要state,由於展現型組件不須要管理數據,但當展現型組件須要管理自身的UI狀態時,例如控制組件內部彈框的顯示與隱藏,是可使用state的,這時的state屬於UI state。既然大部分狀況下展現型組件不須要state,應該優先考慮使用函數組件實現展現型組件。this

容器型組件的職責是:組件數據如何工做。容器型組件須要知道如何獲取子組件所需數據,以及這些數據的處理邏輯,並把數據和邏輯經過props提供給子組件使用。容器型組件通常是有狀態組件,由於它們須要管理頁面所需數據。spa

例如,下面的例子中,UserListContainer是一個容器型組件,它獲取用戶列表數據,而後把用戶列表數據傳遞給展現型組件UserList,由UserList負責UI的展示。設計

class UserListContainer extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      users: []
    }
  }
  
  componentDidMount() {
    var that = this;
    fetch('/path/to/user-api').then(function(response) {
      response.json().then(function(data) {
        that.setState({users: data})
      });
    });
  }

  render() {
    return (
      <UserList users={this.state.users} />
    )
  }
}

function UserList(props) {
  return (
    <div>
      <ul className="user-list">
        {props.users.map(function(user) {
          return (
            <li key={user.id}>
              <span>{user.name}</span>
            </li>
          );
        })}
      </ul>
    </div>
  )  
}

展現型組件和容器型組件是能夠互相嵌套的,展現型組件的子組件既能夠包含展現型組件,也能夠包含容器型組件,容器型組件也是如此。例如,當一個容器型組件承擔的數據管理工做過於複雜時,能夠在它的子組件中定義新的容器型組件,由新組件分擔數據的管理。展現型組件和容器型組件的劃分徹底取決於組件所作的事情。

總結

經過上面的介紹,能夠發現這三組概念有不少重疊部分。這三組概念都體現了關注點分離的思想:UI展示和數據邏輯的分離。函數組件、無狀態組件和展現型組件主要關注UI展示,類組件、有狀態組件和容器型組件主要關注數據邏輯。但因爲它們的劃分依據不一樣,它們並不是徹底等價的概念。它們之間的關聯關係能夠概括爲:函數組件必定是無狀態組件,展現型組件通常是無狀態組件;類組件既能夠是有狀態組件,又能夠是無狀態組件,容器型組件通常是有狀態組件。

下篇預告:

React 深刻系列3:State 和 Props


個人新書《React進階之路》已上市,請你們多多支持!
連接:京東 噹噹

圖片描述

相關文章
相關標籤/搜索