簡稱HOC,全稱 High Order Component。做用是給react組件增減props屬性。react
爲何不先說怎麼寫?恩,由於你其實已經用過了,舉個例子:redux
// App.js import {connect} from 'react-redux'; class App extends React.Component { render() {} } export default connect()(App);
熟悉不?redux的鏈接器。不過筆者有潔癖,喜歡用裝飾器:瀏覽器
// App.js import {connect} from 'react-redux'; @connect() export class App extends React.Component { render() {} }
從connect()()
能夠看出,connect是一個函數,返回值是個react組件。這麼聰明,好佩服本身啊。app
// myHoc.js import React from 'react'; export const myHoc = () => { return (Wrapped) => { class Hoc extends React.Component { render() { return <Wrapped {...this.props}>; } } return Hoc; }; };
是的,高階組件的雛形,就是函數裏隱藏了一個react組件,而參數Wrapped
是什麼?就是下面被裝飾的組件:函數
// App.js @myHoc() export class App extends React.Component { render() {} }
恩恩,表現形式和redux的connect如出一轍。
因此用了高階組件後,export出去的再也不是你本身寫的App(Class),而是最後一個高階。this
好的啦,如今用myHoc給App組件加點料:code
// myHoc.js export const myHoc = () => { return (Wrapped) => { class Hoc extends React.Component { render() { return <Wrapped {...this.props} whoAmI="原罪">; } } return Hoc; }; };
// App.js @myHoc() export class App extends React.Component { render() { return <div>{this.props.whoAmI}</div>; } }
放心,此刻瀏覽器裏已經把個人名字 原罪 打印出來了。component
是的,寫完一個hoc以後,你就會有寫第二個的需求,那就一塊兒用呢:console
// App.js @myHoc() @yourHoc() @hisHoc() @herHoc() export class App extends React.Component { render() { return <div>{this.props.whoAmI}</div>; } }
這就是筆者爲啥要用裝飾器的緣由,簡潔,看起來舒服,寫起來快,咱們看一下另外一種寫法:class
class App extends React.Component { render() {} } export default myHoc()(yourHoc()(hisHoc()(herHoc()(App))));
本身體會,格式化一下吧:
class App extends React.Component { render() {} } let hoc; hoc = herHoc()(App); hoc = hisHoc()(hoc); hoc = yourHoc()(hoc); hoc = myHoc()(hoc); export default hoc;
寫得累不?來,給你條毛巾擦擦汗
對了,hoc能夠接收參數,好比這樣:
// App.js @myHoc('原罪2號') export class App extends React.Component { render() { return <div>{this.props.whoAmI}</div>; } }
那高階組件怎麼接呢?
// myHoc.js export const myHoc = (name) => { return (Wrapped) => { class Hoc extends React.Component { render() { return <Wrapped {...this.props} whoAmI={name}>; } } return Hoc; }; };
我把hoc接收到的參數又返還給了App組件,那如今瀏覽器輸出的就是:原罪2號。
如今,你可能有一個大膽的插法..哦不,想法,就是@myHoc後面能夠不加括號嗎?是哦,看前面幾個案例,都是@myHoc()
。好的,看個人:
// myHoc.js export const myHoc = (Wrapped) => { class Hoc extends React.Component { render() { return <Wrapped {...this.props} whoAmI="原罪">; } } return Hoc; };
// App.js @myHoc export class App extends React.Component { render() { return <div>{this.props.whoAmI}</div>; } }
細心的看官看一下myHoc.js和帶參數的時候有什麼區別。是的,少了一層回調。若是你的高階組件不須要帶參數,這樣寫也是很ok的。
你可能須要拿被裝飾的組件的state數據或者執行它的方法。那麼須要創建一個引用:
// myHoc.js import React from 'react'; export const myHoc = () => { return (Wrapped) => { class Hoc extends React.Component { appRef = null; componentDidMount() { // 能夠對被myHoc裝飾的組件作羞羞的事情了,:) console.log(this.appRef); } render() { return <Wrapped {...this.props} ref={(app) => {this.appRef = app}} >; } } return Hoc; }; };
注意: 在多個高階組件裝飾同一個組件的狀況下,此法並不奏效。你拿到的ref是上一個高階組件的函數中臨時生成的組件。並且在大多數狀況下,你並不知道某個組件會被多少個高階裝飾!
當項目中多處用到某個邏輯方法,可是這個邏輯不能放到util裏的時候,HOC適合你。一個HOC最好只作一件事,這樣維護方便