React 重溫之Render Props

背景

React 16+ 版本更新後,新增了許多有意思的功能,做爲一個苦逼哈哈的前端,也只能與時俱進的繼續學習學習了。前端

什麼是 Render Props

先看官方是怎麼說的:函數

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組件能控制了。

被注入UI組件

而後就是一個使用數據源的組件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。爲何是單向依賴呢? 雙向依賴怎麼辦? 雙向依賴就把狀態維護交給父組件了,誰還那麼麻煩啊!

好難啊,能不能不用

固然能夠不用了,這技術就不鼓勵使用,那有沒有別的方式能夠避免使用這個技術呢? 固然能夠了,單向依賴只是雙向依賴的一種簡單子集,把須要依賴的狀態提到父組件管理就行了,只是麻煩一點而已。

one more thing

若是使用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,並使用類函數

相關文章
相關標籤/搜索