React Render Props 模式


概述

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

如果喜歡請關注

謝謝閱讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM