讓 render-xxx 模式均可以互換。javascript
全部上面提到的三種模式都是爲了處理 mixin 要處理的問題的。在咱們繼續以前,咱們來看一些例子。java
若是你已經掌握這兩個概念,能夠直接跳過這一節看後面的內容react
首先,咱們來寫一個組件來記錄 count,並繪製 render prop 裏的繪製都在 render 方法裏調用了。git
class CounterComponent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } update = type => { if (type === "Inc") { this.setState(({ count }) => ({ count: count + 1 })); } else if (type === "Dec") { this.setState(({ count }) => ({ count: count - 1 })); } }; render() { return this.props.render({ ...this.state, ...this.props, update: this.update }); } }
注意:callback 屬性也能夠叫個別的名字,不必定就是 render。只不過這個模式叫作 render prop。github
接下來咱們須要一個組件來把須要的內容繪製到屏幕上:this
const Counter = ({ count, update }) => { <div> <button onClick={() => update("Inc")}>Inc</button> {count} <button onClick={() => update("Dec")}>Dev</button> </div>; };
Counter
組件接受 count 值和一個 update 方法,而後顯示一個增長、一個減小按鈕以及當前的 count 值。code
最後咱們能夠用CounterComponent
組件來給Counter
增長一些其餘的功能:component
render( <CounterComponent render={props => <Counter {...props} />>} />, document.getElementById('root') );
上文講解了 render prop 模式。如今來看看怎麼使用高階組件來達到一樣的目的。ip
const withCounter = Component => class Hoc extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } update = type => { if (type === "Inc") { this.setState(({ count }) => ({ count: count + 1 })); } else if (type === "Dec") { this.setState(({ count }) => ({ count: count - 1 })); } }; render() { return <Component {...this.state} {} /> } };
看上面的例子,咱們能夠要把須要繪製的組件放到另一個全新的組件裏面去。在這個新的組件裏包含了增強的 state 和 props 等內容。get
const CounterExample = withCounter(Counter); render(<CounterExample />, document.getElementById("root"));
目前咱們已經覆蓋了基本的概念。咱們可使用不一樣的模式來達到相同的目的。下面咱們來關注一下如何讓這幾個模式達到互換的目的。
有的時候你用的庫提供了一個高級組件,可是你最喜歡的是經過JSX的方式來使用組件。有時會遇到一個提供了 render props 的庫,可是你喜歡的是高階組件。一個頗有趣的事實是這些模式能夠幻想轉換。
咱們來根據上面的例子來加一些方法可讓高階組件和 render props 模式能夠互相轉換。
fromHoc: HOC -> RenderProp toHoc: RenderProp -> HOC
toHoc
方法能夠歸結爲:
toHoc: Render => Comp => props => ( <Render {...Props} render={props => <Comp {...props} />} /> );
你也能夠看使用 Render Props來做爲替代實現。
它會把一個 render prop 模式轉化爲高階組件。
const withCounter = toHoc(CounterComponent); const CounterExample = withCounter(Counter);
從高階組件轉化爲 render prop 有一點麻煩。咱們須要把一個 render prop 的組件傳入到高階組件裏。多虧了 Brent Jackon 的這篇文章。
fromHoc: hoc => { class Render extends React.Component { render() { return this.props.children(this.props); } } return hoc(Render); };
或者,使用兩外一種不用 class 的方式。此次要感謝 Rodrigo Pombo 的這個例子。
fromHoc: hoc => hoc(props => props.render(props));
咱們能夠寫一個輕量的 helper 方法來實現高階組件和 renderprops 的轉化。注意,咱們也能夠在初始化 toHoc 方法的時候使用另外的 render name,由於 render prop 能夠能有一個不同的名字,或者是一個子 prop。
const iso = { fromHoc: hoc => hoc(props => props.render(props)), toHoc: Render => Compo => props => ( <Render {...props} render={props => <Comp {...props} />} /> ) };
Render prop,回調繪製和高階組件都是能夠互換的。大多數的時候 render props 能夠知足要求。可是你也能夠經過某些方法讓它在這些模式之間互相轉換。
很是感謝 Brent Jackson,Kent C. Dodds 以及 Rodrigo Pombot 提供了fromHoc
方法的實現,幫咱們解決了很多的問題。