React Render Props 模式

Monster000發表於2019-03-02

概述

Render Props模式是一種非常靈活複用性非常高的模式,它可以把特定行為或功能封裝成一個元件,提供給其他元件使用讓其他元件擁有這樣的能力,接下來我們一步一步來看React元件中如何實現這樣的功能。

React 元件資料傳遞

React中我們可以給一個元件傳遞一些props並且在元件內部展示,同樣的我們也可以傳遞一些元件同樣也是行得通的,一起看一個例子

1. 元件普通資料傳遞

我們可以通過元件傳遞一些字串資料,並且在元件內部渲染
下面的程式碼很平常,我們絕大多數程式碼都是這樣。

const Foo = ({ title }) => (
  <div>
    <p>{title}</p>
  </div>
);
class App extends React.Component {
  render() {
    return (
      <div>
        <h2>這是一個示例元件</h2>
        <Foo title="大家好,我是土豆" />
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById(`app`))
複製程式碼

2. 元件上傳遞元件

更進一步,我們可以在元件上傳遞普通的HTML 標籤React 元件達到複用的目的

// https://codepen.io/tudou/full/OvdrPW
const Bar = () => (<p>我是Bar元件 :)</p>);
const Foo = ({ title, component }) => (
  <div>
    <p>{title}</p>
    {component()}
  </div>
);
class App extends React.Component {
  render() {
    return (
      <div>
        <h2>這是一個示例元件</h2>
        <Foo title={<p>大家好,我是土豆</p>} component={() => <Bar /> } />
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById(`app`))
複製程式碼

在上面的例子中傳遞普通的HTML 標籤對我們複用元件沒有任何幫助,重點可以看傳遞component這個引數,它傳遞給Foo元件一個函式這個函式返回的是一個Bar 元件,我們會在Foo 元件中呼叫並且顯示component函式中的元件。我們再來寫一個小的DEMO進行驗證。

3. 一個純粹的Render Props例子

// https://codepen.io/tudou/full/dmawvY
const Bar = ({ title }) => (<p>{title}</p>);

class Foo extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: `我是一個state的屬性` };
  }
  render() {
    const { render } = this.props;
    const { title } = this.state;
    
    return (
      <div>
        {render(title)}
      </div>
    )
  }
}

class App extends React.Component {
  render() {
    return (
      <div>
        <h2>這是一個示例元件</h2>
        <Foo render={(title) => <Bar title={title} />} />
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById(`app`))
複製程式碼

在上面的例子中,給Foo 元件傳遞了一個render引數它是一個函式這個函式返回一個Bar元件,這個函式接受一個引數title他來自於Foo 元件呼叫時傳遞並且我們又將title 屬性傳遞給了Bar 元件。經過上述的呼叫過程我們的Bar 元件就可以共享到Foo 元件內部的state 屬性`。

4. 通過children傳遞

這個demo略微不同於上面通過props傳遞,而它是通過元件的children傳遞一個函式給Foo 元件

// https://codepen.io/tudou/full/WzPPeL
const Bar = ({ title }) => (<p>{title}</p>);

class Foo extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: `我是一個state的屬性` };
  }
  render() {
    const { children } = this.props;
    const { title } = this.state;
    
    return (
      <div>
        {children(title)}
      </div>
    )
  }
}

class App extends React.Component {
  render() {
    return (
      <div>
        <h2>這是一個示例元件</h2>
        <Foo>
          {(title) => (
            <Bar title={title} />
          )}
        </Foo>
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById(`app`))
複製程式碼

觀察可發現只是寫法略微有些變法,我們將要傳遞的資料放到的元件的children。實際上並無不同之處(都是傳遞一個函式)

<Foo>
  {(title) => (
    <Bar title={title} />
  )}
</Foo>
複製程式碼

注意事項

請注意當我們的Foo 元件繼承於React.PureComponent的時候,我們需要避免下面這樣的寫法。不然我們的效能優化將付之東流。

render() {
    return (
      <div>
        <h2>這是一個示例元件</h2>
        <Foo render={(title) => <Bar title={title} />} />
      </div>
    );
  }
複製程式碼

如果你在render建立一個函式,在每次渲染的時候render prop將會是一個新的值,那麼每次將會重新渲染Bar

正確的做法應該是在元件內部建立一個函式用於顯示元件

const Bar = ({ title }) => (<p>{title}</p>);

class Foo extends React.Component {
  constructor(props) {
    super(props);
    this.state = { title: `我是一個state的屬性` };
  }
  render() {
    const { render } = this.props;
    const { title } = this.state;
    
    return (
      <div>
        {render(title)}
      </div>
    )
  }
}

class App extends React.Component {
  // 單獨建立一個渲染函式
  renderFoo(title) {
    return <Bar title={title} />;
  }
  render() {
    return (
      <div>
        <h2>這是一個示例元件</h2>
        <Foo render={this.renderFoo} />
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById(`app`))
複製程式碼

總結

學習瞭解Render Props渲染模式原理,使用了renderchildren兩種不同的渲染方法。

更新詳細的官方例子請參考https://reactjs.org/docs/render-props.html

官方例子線上參考 https://codesandbox.io/embed/1075p1yov3

如果喜歡請關注

謝謝閱讀

相關文章