react 高階元件的 理解和應用

heart_of_time發表於2018-05-16

高階元件是什麼東西

  簡單的理解是:一個包裝了另一個基礎元件的元件。(相對高階元件來說,我習慣把被包裝的元件稱為基礎元件)

  注意:這裡說的是包裝,可以理解成包裹和組裝;

  具體的是高階元件的兩種形式吧:

    a、屬性代理(Props Proxy)

      可以說是對元件的包裹,在包裹的過程中對被包裹的元件做了點什麼(props的處理,把基礎元件和其他元素組合),然後返回,這就成了一個高階元件;

    b、反向繼承 (Inheritance Inversion)

      可以理解成是組裝,和屬性代理不同的是,反向繼承是繼承自基礎元件,所有很自然,它可以直接獲取基礎元件的props,操作基礎元件的state。可以通過 反向繼承的形式,配合compose將攜帶不同功能模組的高階元件組裝到基礎元件上,加強基礎元件。


   本文栗子:https://github.com/wayaha/react-demos-HOC

  compose栗子:https://github.com/wayaha/react-dom-compose

  (如果對您有幫助,請幫我點顆star)

   下邊一個一個的說。

屬性代理(Props Proxy)

  我們可以先建一個基礎元件,如下

 
class BaseComponent extends Component {
  constructor (props) {
    super(props);
    this.state = {
      baseName: `base component`
    };
  };

  render () {
    const { name} = this.props;
    const { baseName } = this.state;
    return <div>{`${name} + ${baseName}`}</div>
  };
};

  為了便於說明問題,寫一個很簡答的基礎元件,它的作用僅僅是返回一個div,顯示他自己的名字;

  a、對props的操作

     這個高階元件是一個相對簡單的無狀態元件,只是這個高階元件返回了一個新的元件,而這個新的元件是對基礎元件的一個包裝。僅僅對基礎元件的props進行了增加,當然也可以進行改變,刪除和讀取(具體的可以下載程式碼上手試試)。

    注意:(1)、此時render方法內的this.props,它是InnerComponent組建的props,而BaseComponent元件實際也就是InnerComponent元件。

       (2)、高階元件中的InnerComponent元件是一個完整的元件,可以根據需要新增一下state狀態,作為props傳到BaseComponent元件。可以將基礎元件作為一個公共的元件,然後根據需要,使用的不同的高階元件包裝出具有不一樣功能的元件。

import React, { Component } from `react`;

const PropsComponent = (BaseComponent) => {

  class InnerComponent extends Component {
    render () {
      const props = {
        …this.props,
        name: `HOC Component`
      };
      return <BaseComponent {…props} />
    };
  };

  return InnerComponent;
}
export default PropsComponent;

  b、把基礎元件和其他元素組合

    出於操作樣式、佈局或其它的考慮,可以將 基礎元件與其它元件包裹在一起。一些相對簡單的用法也可以使用正常的父元件來實現,只是使用高階元件可以獲得更多的靈活性。也利於元件的抽象和複用。

const WrapperComponent = (BaseComponent) => {
    class InnerComponent extends Component {
        render () {
            const props = {
                ...this.props,
                name: `HOC Component`
            };
            return <div style={{backgroundColor: `orange`}}>
                    <BaseComponent {...props} />
                </div>
        };
    };
    return InnerComponent;
}

反向繼承(Inheritance Inversion)

  反向繼承是繼承自基礎元件,並不是高階元件繼承傳入的基礎元件,所以成為反向繼承。由於高階元件繼承了基礎元件,那麼高階元件通過this可以操作基礎元件的state,props以及基礎元件的方法,甚至可以通過super來操作基礎元件的生命週期。

  a、渲染劫持

    所謂渲染劫持就是,高階元件控制了基礎元件渲染生成的結果,因為基礎元件的渲染被控制,高階元件就可以對它做點什麼。。。比如:

      (1)、看心情(根據條件),控制渲染的結果;

      (2)、改變dom樹的樣式;

      (3)、改變基礎元件中一下被渲染元素的props;

      (4)、操作dom樹中的元素。

    這個就是根據props傳入的條件來決定要不要渲染。

const HOCComponent = (BaseComponent) => {
  return class Enhancer extends BaseComponent{
    render() {
      if (this.props.loggedIn) {
        return super.render()
      } else {
        return null
      }
    }
  }
}

 

  通過super.render()獲取基礎元件的dom樹,然後就可以進行一些操作,改變dom樹的樣式,改變基礎元件中一下被渲染元素的props,操作dom樹中的元素等等。

HOCComponent = (BaseComponent) => {
  return class Enhancer extends BaseComponent {
    render() {
      const domsTree = super.render()
      let newProps = {};
      if (domsTree && domsTree.type === `input`) {
        newProps = {value: `this is new value`}
      }
      const props = Object.assign({}, domsTree.props, newProps)
      const newDomsTree = React.cloneElement(domsTree, props, domsTree.props.children)
      return newDomsTree
    }
  }
}

  b、操作state 

    高階元件可以讀取、編輯和刪除 基礎元件 例項的 state,如果你需要,你也可以給它新增更多的 state。需要注意的是,這會搞亂基礎元件 的 state,導致你可能會破壞某些東西。所以,要限制高階元件讀取或新增 state,新增 state 時應該放在單獨的名稱空間裡,而不是和基礎元件的 state 混在一起。

 

另外,高階元件配合compose實現功能模組化,和個功能模組的隨意組合使用。(見上文github例子)

  每一個高階元件封裝一種功能,例如例子中的AddStaff,ChangeStaffData,DeleteStaff,ShowStaffMsg,可以根據需要將高階元件組合到任意的基礎元件中,實現功能模組化,也方便程式碼的抽離和複用。

相關文章