在接觸過React項目後,大多數人都應該已經瞭解過或則用過了HOC(High-Order-Components)和FaCC(Functions as Child Components),由於這兩個模式在大多數react的開源庫裏都存在。好比react-router裏面的withRouter 就是典型的高階組件,接受一個組件返回另一個通過加強後的組件。而react-motion中的Motion就是典型的FaCC的應用。html
HOC和FaCC二者作的事也是很是類似的,都是相似設計模式裏面的裝飾者模式。都是在原有的實例或則單元上進行功能的加強。react
固然不僅是一些開源庫中會使用,在日常的代碼編寫中,也有不少地方是適用於使用HOC和FaCC去封裝一些邏輯。好比數據埋點,新特性的toggle,獲取轉換數據等。對於加強代碼可讀性和邏輯複用來講,很是有用的。git
高階函數咱們都用過,就是接受一個函數而後返回一個通過封裝的函數:github
const plus = first => second => (first + second) plus(1)(2) // 3
而高階組件就是高階函數的概念應用到高階組件上:express
const withClassName = ComposedComponent => props => ( <ComposedComponent {...props} className='demo-class' /> ) // 使用 const Header = text => (<header>{text}</header>) const headerWitheClass = withClassName(Header)
接受一個組件返回一個通過包裝的新組件。在咱們常用的withRouter
就是在原有組件props
上面在加上localtion
等屬性。除了添加props之外高階組件還能作到:設計模式
對於上面的前三點都比較好理解,解釋一下第4點。好比你在render了一個頁面以後,須要改變一下頁面的title.這是單頁應用廣泛存在的一個需求,一般你能夠在具體router庫中使用hook去實現。固然也能夠經過HOC來實現:性能優化
const withTitleChange = ComposedComponent => { return class extends React.Component { componentDidMount () { const { title } = this.props document.title = title } render () { const props = this.props return <ComposedComponent {...props} /> } } }
一樣FaCC也是用於加強原有組件能力的一種模式,其主要功能的實如今於react的props.children能夠是任何東西,包括函數。咱們能夠拿上面class的例子用FaCC再實現一遍:react-router
const ClassNameWrapper = ({ children }) => children('demo-class') // 使用 const HeadWithClass = (props) => ( <ClassNameWrapper> {(class) => <header classNmae={class} ></header>} </ClassNameWrapper> )
在FaCC中你也能夠像HOC同樣在生命週期中作不少事對原有的組件進行封裝,基本上HOC能作的FaCC也都能作。我所在的項目以前都是大範圍的使用HOC,再通過一番討論後,開始大範圍的轉變成FaCC。app
二者都是用來加強原有組件的,具體該使用那種?那種是正確的模式?社區關於這一點也有不少討論,好比就有人說FaCC是反模式:Function as Child Components Are an Anti-Pattern。他給出的理由是children並不語義化,會形成困惑,而後他提出了Component Injection
的模式,有興趣的同窗能夠讀一讀。dom
具體從幾個方面作一下對比:
組合階段意思就是HOC,FaCC和要被加強的組件的組合時候。能夠很明顯發現,FaCC對於先後組件對接依賴信息顯示的更多,相對而言更容易理解。而HOC,相互之間如何橋接,你必須得深刻到HOC內部讀代碼才能夠知道這個HOC具體幹了啥。
// HOC example import View from './View' const DetailPage = withServerData(withNavigator(View))
// FaCC example import View from './View' const DetailPage = props => ( <FetchServerData> { data => ( <Navigator> <View data={data} {...props} /> </Navigator> ) } </FetchServerData> )
若是在上面再增長2個HOC,上面組合的過程就變得十分難看。而FaCC相對而言,如何封裝,數據源來自那裏,組件接受了那些數據都比較顯眼。
在HOC中咱們能接受到宿主的prop,由於props是從HOC往下傳遞的,因此咱們也有完整的生命週期,咱們可使用shouldComponentUpdate優化。而FaCC則否則,沒法在其內部作比較props,除非在組合的時候外部在包一個組件才能進行比較props。
FaCC 在組合階段相對HOC更爲靈活,他並不規定被加強組件如何使用它傳遞下去的屬性。而HOC基本上在編寫完後就定死了。
另外,FaCC不會再去建立一個新的Component,而HOC會建立一個新的Component而後傳遞props下去。
社區中不少開源庫已經使用了兩種模式,也有不少的文章進行比較。也有不少激烈討論,固然對於最後解決問題而言,兩種模式都有好處。出於不一樣的考慮,可能選擇不同。
參考文章: