React 16+ 版本更新後,新增了許多有意思的功能,做爲一個苦逼哈哈的前端,也只能與時俱進的繼續學習學習了。前端
先看官方是怎麼說的:函數
The term 「render prop」 refers to a simple technique for sharing code between React components using a prop whose value is a function.
翻譯成大白話就是:這個技術呢,很簡單,就是給組件添加一個值爲函數的屬性,這個函數能夠在組件渲染(render)的時候調用,那這個組件是幹啥用的呢?就是爲了給原有組件「注入」其它組件的代碼。性能
看完官方的說法,想必是一頭霧水,爲啥要經過這麼麻煩的方式給一個組件「注入」另外一個組件的代碼?React不是本來就支持組件嵌套和傳值嗎?學習
人官方網站也說了,這個技術只是用來解決一些比較特殊的問題的,並非讓你沒事就用的, 那麼咱們可能就要問了,何時要用呢?動畫
一樣套用官方的說法:網站
a render prop is a function prop that a component uses to know what to render.
翻譯過來就是說,這個渲染屬性就是讓組件知道本身渲染什麼東西。。。 這不廢話嘛!別急,還有大白話翻譯呢。this
大白話翻譯過來就是說啊:若是你一個組件不知道本身渲染什麼東西,或者說你一個組件的基礎功能是提供」可變數據源「,具體展現UI能夠從外部注入,那麼就能夠用這個技術了。 是否是仍是一臉懵?一頭霧?不要緊,看個官方例子好了。翻譯
首先是一個Mouse組件,能夠實時獲取鼠標位置並展現出來,那麼在這裏,這個Mouse組件提供」可變數據源「,也就是跟隨鼠標一直變化的鼠標位置。code
那你在頁面渲染個鼠標位置有什麼用啊?誰沒事兒盯着你頁面看鼠標位置啊?可是咱們可用鼠標位置作許多用意思的東西啊,好比說跟隨鼠標移動的動畫啊,拖動頁面元素移動啊什麼的。。。component
在這裏,咱們說Mouse組件提供「可變數據源」,可是它並不知道本身要渲染什麼,它只是一個基礎數據的提供者。
class Mouse extends React.Component { constructor(props) { super(props); this.handleMouseMove = this.handleMouseMove.bind(this); this.state = { x: 0, y: 0 }; } handleMouseMove(event) { this.setState({ x: event.clientX, y: event.clientY }); } render() { return ( <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}> {/* ...but how do we render something other than a <p>? */} <p>The current mouse position is ({this.state.x}, {this.state.y})</p> {this.props.render(this.state)} // 這個比較關鍵 </div> ); } }
咱們看到在組件的渲染方法(render)裏,沒什麼有價值的東西,但有一行代碼很關鍵{this.props.render(this.state)}
, 這是什麼意思?
很簡單,調用Mouse組件的props裏的render函數(這個render就是咱們前面說的 「一個值爲函數的屬性」 ,叫啥名兒都行,叫render是湊巧了,誰讓這個技術起碼是Render Props呢)來往這裏渲染UI,Mouse只負責把「可變數據源」做爲參數給render函數(props裏面的屬性函數,可不是聲明週期的render函數)就行了。至於渲染的內容是什麼?那就不是Mouse組件能控制了。
而後就是一個使用數據源的組件Cat了,讓Cat圖片跟隨鼠標位置的變化而移動。怎麼變?固然是使用Mouse組件提供的可變數據源了。
這個Cat組件就是咱們但願渲染在頁面的UI了。之後可能會有dog、pig之類的,都須要用到Mouse提供的基礎數據,也就是「可變數據源」。可是Cat並不能獲取Mouse的數據變更啊,怎麼把這倆綁定(聯繫)在一塊兒呢?
class Cat extends React.Component { render() { const mouse = this.props.mouse; return ( <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} /> ); } }
而後就是綁定的出場了,說綁定有點不太合適,說調用可能更符合實際狀況一點,以前咱們在Mouse的render函數(生命週期函數)裏調用了組件Props上的render屬性函數(自定義的,叫啥名兒都行),那麼咱們在用到Mouse組件的時候,給Mouse組件一個render屬性函數,這個函數使用參數(鼠標位置,經過Mouse組件的state傳過來)來初始化Cat組件,而後返回。那麼這樣一來Cat組件就內嵌在Mouse組件的render函數裏了。
也便是說一直到這個時候,咱們才知道要往Mouse組件裏渲染什麼UI。
class MouseTracker extends React.Component { render() { return ( <div> <h1>Move the mouse around!</h1> <Mouse render={mouse => ( <Cat mouse={mouse} /> )}/> </div> ); } }
放心,通常狀況這個技術用是用不上的,這輩子都不可能用上。。。但還有不通常狀況呢不是嗎?
簡單來講,當兩個平級組件之間須要單向依賴的時候,就能夠用這個技術了。
那什麼是平級依賴呢? 很簡單,就是連個同級組件A、B,A組件須要跟隨B組件的內部狀態來改變本身的內部狀態,咱們就說A依賴B。爲何是單向依賴呢? 雙向依賴怎麼辦? 雙向依賴就把狀態維護交給父組件了,誰還那麼麻煩啊!
固然能夠不用了,這技術就不鼓勵使用,那有沒有別的方式能夠避免使用這個技術呢? 固然能夠了,單向依賴只是雙向依賴的一種簡單子集,把須要依賴的狀態提到父組件管理就行了,只是麻煩一點而已。
若是使用render Props技術的組件(也就是有一個render函數屬性的組件)是繼承自React.PureComponent 的,那麼在props的淺比較看來,新老props老是不同的,那麼就會每次都從新渲染,性能開銷比較大。
因此推薦用法以下:
class MouseTracker extends React.Component { // Defined as an instance method, `this.renderTheCat` always // refers to *same* function when we use it in render renderTheCat(mouse) { return <Cat mouse={mouse} />; } render() { return ( <div> <h1>Move the mouse around!</h1> <Mouse render={this.renderTheCat} /> </div> ); } }
繼承React.Component,並使用類函數