REACT組件抽象與複用

當咱們在說組件抽象與複用的時候咱們在說什麼?本質就是組件的拆分。。css

爲何拆

「分而治之」是一個好策略。可是不要濫用,只有必要的時候纔去拆分組件, 否則可能得不償失 。html

拆分原則

高內聚低耦合 。

高內聚:就是把邏輯緊密相關的內容放在一個組件中。這段js,css,html都是爲了實現同一個功能咱們把它放在一個js文件裏。react天生具備高內聚的特色。react

低耦合:指的是不一樣組件之間的依賴關係要儘可能弱化,也就是每一個組件要儘可能獨立 。 保持整個系統的低耦合度,須要對系統中的功能有充分的認識,而後根據功能點劃分模 塊,讓不一樣的組件去實現不一樣的功能json

科普組件分類

函數組件(Functional Component )和類組件(Class Component)

劃分依據是根據組件的定義方式。redux

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

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

類組件能夠維護自身的狀態變量,即組件的state,類組件還有不一樣的生命週期方法,可讓開發者可以在組件的不一樣階段(掛載、更新、卸載),對組件作更多的控制。 類組件這麼強大,首選類組件? 不,函數組件更加專一和單一,承擔的職責也更加清晰,它只是一個返回React 元素的函數,只關注對應UI的展示。函數組件接收外部傳入的props,返回對應UI的DOM描述,僅此而已。 函數組件的使用能夠從思想上迫使你在設計組件時多作思考,更加關注邏輯和顯示的分離,設計出更加合理的頁面上組件樹的結構。實際操做上,當一個組件不須要管理自身狀態時,能夠把它設計成函數組件,當你有足夠的理由發現它須要「升級」爲類組件時,再把它改造爲類組件。api

無狀態組件(Stateless Component )和有狀態組件(Stateful Component)

劃分依據是根據組件內部是否維護state。無狀態組件內部不使用state,只根據外部組件傳入的props返回待渲染的React 元素。有狀態組件內部使用state,維護自身狀態的變化,有狀態組件根據外部組件傳入的props和自身的state,共同決定最終返回的React 元素。函數組件必定是無狀態組件,類組件則既能夠充當無狀態組件,也能夠充當有狀態組件數組

展現型組件(Presentational Component)和容器型組件(Container Component)

劃分依據是根據組件的職責.bash

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

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

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展示,類組件、有狀態組件和容器型組件主要關注數據邏輯。

它們之間的關聯關係能夠概括爲:函數組件必定是無狀態組件,展現型組件通常是無狀態組件;類組件既能夠是有狀態組件,又能夠是無狀態組件,容器型組件通常是有狀態組件。

tips:受控組件與非受控組件,業務組件,ui組件,

實現

高階組件( Higher Order Component, HOC)

並非 React提供的某種 API,而是使 用 React 的一種模式,用於加強現有組件的功能 簡單來講,一個高階組件就是一個函數,這個函數接受一個組件做爲輸入,而後返回一個新的組件做爲結果,並且,返回的新組件擁有了輸入組件所不具備的功能 。 這裏提到的組件指的並非組件實例,而是一個組件類,也能夠是一個無狀態組件 的函數

import React from ’ react ’ J
function removeUserProp(WrappedComponent) {
  return class WrappingComponent extends React.Component {
    render() {
      const {user, ... otherProps} = this.props; 
      return <WrappedComponent {... otherProps) />
     }
}
export default removeUserProp;
複製代碼

分類

根據返回的新組件和傳人組件參數的關係,高階組件的實現方式能夠分爲兩大類:

代理方式的 高階組件 :

上面的 removeUserProp例子就是一個代理方式的高階組件,特色是返回的新組件類 直接繼承自 React.Component類。 新組件扮演的角色是傳入參數組件的一個「代理」,在 新組建的 render 函數中,把被包裹組件渲染出來,除了高階組件本身要作的工做,其他 功能全都轉手給了被包裹的組件 。

function removeUserProp(WrappedComponent) { 
return function newRender(props) {
        const {user, ... otherProps) = props;
     return <WrappedComponent {... otherProps} />
  }
}
複製代碼

應用在下列場景中:

操縱 prop;

訪問 ref:(訪問 ref並非值得推薦的 React組件使用方式)

抽取狀態: 其實,咱們已經使用過「抽取狀態」的高階組件了,就是 react-redux 的 connect 函 數,注意 connect 函數自己並非高階組件, connect 函數執行的結果是另 一個函數,這 個函數纔是高階組件 。

包裝組件 。

const styleHOC = (WrappedComponent, style) => {
return class HOCComponent extends React.Component {
    render() { 
    return (
        <div style={style}>
         <WrappedComponent {... this.props}/>
        </div>
    }
 }
}
複製代碼

繼承方式的高階組件 。

class PureComponent extends Component{
    shouldComponentUpdate(nextProps,nextState){
     const {props,state} = this;
     return shallowCompare(nextProps,props) && shallowCompare(nextState,state)
        
    }
}
複製代碼
const modi fyProps HOC = (WrappedComponent) => {
    return class NewComponent extends WrappedComponent {
        render() {
        const elements= super.render() ;
        const newStyle = {
          color: (elements && elements.type ===’div’)?’red’:’green’
        }
        const newProps = { ... this.props, style: newStyle};
         return React.cloneElement(elements, newProps,elements.props.children);
        }
    }
}
複製代碼

代理方式更加容易實現和控制,繼承方式的惟一優點是能夠操縱特定組件的生命週期函數。 「優先考慮組合,而後才考慮繼承 。」

以函數爲子組件

const loggedinUser = ’ mock user ’;
class AddUserProp extends React.Component {
    render() {
        const user = loggedinUser ;
        return this.props.children(user);
    }
}
AddUserProp.propTypes = {
 children: React.PropTypes.func.isRequired
}
複製代碼

這個類的代碼,和被加強組件的惟一聯繫就是 this.props.children,並且 this.props. children是函數類型,在 render 函數中 直接調用 this.props.children 函數 ,參數就是咱們 但願傳遞下去的 user。 使用這個 AddUserProp 的靈活之處在於它沒有對被加強組件有任何 props 要求,只 是傳遞一個參數過去,至於怎麼使用,徹底由做爲子組件的函數決定

裝飾器

其餘

mixin

extands

相關文章
相關標籤/搜索