高階元件是什麼東西
簡單的理解是:一個包裝了另一個基礎元件的元件。(相對高階元件來說,我習慣把被包裝的元件稱為基礎元件)
注意:這裡說的是包裝,可以理解成包裹和組裝;
具體的是高階元件的兩種形式吧:
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)
我們可以先建一個基礎元件,如下:
為了便於說明問題,寫一個很簡答的基礎元件,它的作用僅僅是返回一個div,顯示他自己的名字;
a、對props的操作
這個高階元件是一個相對簡單的無狀態元件,只是這個高階元件返回了一個新的元件,而這個新的元件是對基礎元件的一個包裝。僅僅對基礎元件的props進行了增加,當然也可以進行改變,刪除和讀取(具體的可以下載程式碼上手試試)。
注意:(1)、此時render方法內的this.props,它是InnerComponent組建的props,而BaseComponent元件實際也就是InnerComponent元件。
(2)、高階元件中的InnerComponent元件是一個完整的元件,可以根據需要新增一下state狀態,作為props傳到BaseComponent元件。可以將基礎元件作為一個公共的元件,然後根據需要,使用的不同的高階元件包裝出具有不一樣功能的元件。
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,可以根據需要將高階元件組合到任意的基礎元件中,實現功能模組化,也方便程式碼的抽離和複用。