欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React RenderProps模式超詳細(xì)講解

 更新時(shí)間:2022年11月11日 17:03:45   作者:夏天的味道123  
render props是指一種在 React 組件之間使用一個(gè)值為函數(shù)的 prop 共享代碼的技術(shù)。簡單來說,給一個(gè)組件傳入一個(gè)prop,這個(gè)props是一個(gè)函數(shù),函數(shù)的作用是用來告訴這個(gè)組件需要渲染什么內(nèi)容,那么這個(gè)prop就成為render prop

render prop是一個(gè)技術(shù)概念。它指的是使用值為function類型的prop來實(shí)現(xiàn)React component之間的代碼共享。

如果一個(gè)組件有一個(gè)render屬性,并且這個(gè)render屬性的值為一個(gè)返回React element的函數(shù),并且在組件內(nèi)部的渲染邏輯是通過調(diào)用這個(gè)函數(shù)來完成的。那么,我們就說這個(gè)組件使用了render props技術(shù)。

<DataProvider render={data => (
  <h1>Hello {data.target}</h1>
)}/>

不少類庫都使用了這種技術(shù),比如說:React Router和Downshift。

在這個(gè)文檔里面,我們將會(huì)討論為什么render props是如此有用,你該如何編寫自己的render props組件。

正文

使用Render Props來完成關(guān)注點(diǎn)分離

在React中,組件是代碼復(fù)用的基本單元(又來了,官方文檔不斷地在強(qiáng)調(diào)這個(gè)準(zhǔn)則)。到目前為止,在React社區(qū)里面,關(guān)于共享state或者某些相似的行為(比如說,將一個(gè)組件封裝進(jìn)另一擁有相同state的組件)還沒有一個(gè)明朗的方案。

舉個(gè)例子,下面這個(gè)組件是用于在web應(yīng)用中追蹤鼠標(biāo)的位置:

class MouseTracker 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}>
        <h1>Move the mouse around!</h1>
        <p>The current mouse position is ({this.state.x}, {this.state.y})</p>
      </div>
    );
  }
}

隨著光標(biāo)在屏幕上面移動(dòng),這個(gè)組件將會(huì)在文檔的<p>標(biāo)簽里面顯示當(dāng)前光標(biāo)在x,y軸上的坐標(biāo)值。

那么問題來了: 我們該如何在別的組件復(fù)用這種行為(指的是監(jiān)聽mouseMove事件,獲取光標(biāo)的坐標(biāo)值)呢?換句話說,如果別的組件也需要知道目前光標(biāo)的坐標(biāo)值,那我們能不能將這種行為封裝好,然后在另外一個(gè)組件里面開箱即用呢?

因?yàn)椋赗eact中,組件是代碼復(fù)用的基本單元(again)。那好,我們一起來重構(gòu)一下代碼,把我們需要復(fù)用的行為封裝到<Mouse>組件當(dāng)中。

// The <Mouse> component encapsulates the behavior we need...
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>
      </div>
    );
  }
}
class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse />
      </div>
    );
  }
}

現(xiàn)在,<Mouse>組件看似把所有跟監(jiān)聽mousemove事件,保存光標(biāo)的坐標(biāo)值等相關(guān)的行為封裝在一起了。實(shí)際上,它還不能達(dá)到真正的可復(fù)用。

假設(shè),我們需要實(shí)現(xiàn)這么一個(gè)組件。它需要渲染出一只用圖片表示的貓去追逐光標(biāo)在屏幕上移動(dòng)的視覺效果。我們可能會(huì)通過向<Cat>組件傳遞一個(gè)叫mouse(它的值為{{x,y}})的prop來獲得當(dāng)前光標(biāo)所在位置。參考React實(shí)戰(zhàn)視頻講解:進(jìn)入學(xué)習(xí)

首先,我們會(huì)在<Mouse>組件的render方法里面插入這個(gè)<Cat>組件,像這樣子:

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 }} />
    );
  }
}
class MouseWithCat 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}>

        {/*          We could just swap out the <p> for a <Cat> here ... but then          we would need to create a separate <MouseWithSomethingElse>          component every time we need to use it, so <MouseWithCat>          isn't really reusable yet.        */}
        <Cat mouse={this.state} />
      </div>
    );
  }
}
class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <MouseWithCat />
      </div>
    );
  }
}

這種方式的實(shí)現(xiàn)可能對個(gè)別的場景有用,但是,我們還是沒有達(dá)成通過封裝讓這種行為真正地復(fù)用的目標(biāo)。在別的應(yīng)用場景下,每一次當(dāng)我們需要獲取光標(biāo)在屏幕上的坐標(biāo)的時(shí)候,我們都需要重新創(chuàng)建一個(gè)組件(例如,一個(gè)跟<MouseWithCat>相似組件)來完成這個(gè)業(yè)務(wù)場景所對應(yīng)的渲染任務(wù)。

這個(gè)時(shí)候,就輪到render props 出場啦:相比直接把<Cat>這個(gè)組件硬編碼到<Mouse>組件當(dāng)中,刻意地去改變<Mouse>組件的UI輸出(也就是我們重新定義一個(gè)<MouseWithCat>組件的原因)。更好的做法是,我們可以給<Mouse>組件定義一個(gè)值為函數(shù)類型的prop,讓這個(gè)prop自己來動(dòng)態(tài)地決定要在Mouse組件的render方法要渲染東西。這個(gè)值為函數(shù)類型的prop就是我們所說的render prop了。

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 }} />
    );
  }
}
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}>

        {/*          Instead of providing a static representation of what <Mouse> renders,          use the `render` prop to dynamically determine what to render.        */}
        {this.props.render(this.state)}
      </div>
    );
  }
}
class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}

現(xiàn)在,相比每一次都要重復(fù)地將<Mouse>組件的代碼復(fù)制一遍,然后將我們要渲染的東西硬編碼到<Mouse>的render方法中去,我們采取了一個(gè)更省力的辦法。那就是給Mouse新增了一個(gè)render屬性,讓這個(gè)屬性來決定要在<Mouse>組件中渲染什么。

更加具體和直白地說,一個(gè)render prop(這里不是代指技術(shù),而是組件屬性) 就是一個(gè)值為函數(shù)類型的prop。通過這個(gè)函數(shù),我們讓掛載了這個(gè)prop的組件知道自己要去渲染什么。

這種技術(shù)使得我們之前想要共享的某些行為(的實(shí)現(xiàn))變得非常之可移植(portable)。假如你想要得到這種行為,你只需要渲染一個(gè)帶render屬性的類<Mouse>組件到你的組件樹當(dāng)中就可以了。剩下的就讓這個(gè)render prop來獲取相關(guān)的數(shù)據(jù)(通過函數(shù)形參被實(shí)例化時(shí)得到。拿上述例子來說,就是(mouse)=> <Cat mouse={mouse}>mouse),然后決定如何干預(yù)這個(gè)組件的渲染。

一個(gè)很有意思的,并值得我們注意的事情是,你完全可以通過一個(gè)帶render屬性的普通組件來實(shí)現(xiàn)大部分的HOC。舉個(gè)例子,假如你在共享行為(監(jiān)聽mousemove事件,獲得光標(biāo)在屏幕上的坐標(biāo))時(shí)不想通過<Mouse>組件來完成,而是想通過高階組件withMouse來完成的話,那么就可以很簡單地通過創(chuàng)建一個(gè)帶render prop的<Mouse>組件來達(dá)成:

// If you really want a HOC for some reason, you can easily
// create one using a regular component with a render prop!
function withMouse(Component) {
  return class extends React.Component {
    render() {
      return (
        <Mouse render={mouse => (
          <Component {...this.props} mouse={mouse} />
        )}/>
      );
    }
  }
}

可以這么說,render props(指技術(shù))讓HOC技術(shù)與其他技術(shù)(在這里,指它自己)的組合使用成為了可能。

render prop的prop名不一定叫render

如上面的標(biāo)題,你要牢牢記住,這種技術(shù)雖然叫render props,但是prop屬性的名稱不一定非得叫“render”。實(shí)際上,只要組件上的某個(gè)屬性值是函數(shù)類型的,并且這個(gè)函數(shù)通過自己的形參實(shí)例化時(shí)獲取了這個(gè)組件的內(nèi)部數(shù)據(jù),參與到這個(gè)組件的UI渲染中去了,我們就說這個(gè)組件應(yīng)用了render props這種技術(shù)。

在上面的例子當(dāng)中,我們一直在使用“render”這個(gè)名稱。實(shí)際上,我們也可以輕易地?fù)Q成children這個(gè)名稱!

<Mouse children={mouse => (
  <p>The mouse position is {mouse.x}, {mouse.y}</p>
)}/>

同時(shí),我們也要記住,這個(gè)“children”prop不一定非得羅列在在JSX element的“屬性”列表中。它實(shí)際上就是我們平時(shí)用JSX聲明組件時(shí)的children,因此你也可以像以前一樣把它放在組件的內(nèi)部。

<Mouse>
  {mouse => (
    <p>The mouse position is {mouse.x}, {mouse.y}</p>
  )}
</Mouse>

在react-motion這個(gè)庫的API中,你會(huì)看到這種寫法的應(yīng)用。

因?yàn)檫@種寫法比較少見,所以假如你這么做了,為了讓看你代碼的人不產(chǎn)生疑惑的話,你可能需要在靜態(tài)屬性propTypes中顯式地聲明一下children的數(shù)據(jù)類型必須為函數(shù)。

Mouse.propTypes = {
  children: PropTypes.func.isRequired
};

注意點(diǎn)

當(dāng)跟React.PureComponent結(jié)合使用時(shí),要當(dāng)心

如果你在組件的render方法里面創(chuàng)建了一個(gè)函數(shù)的話,然后把這個(gè)函數(shù)賦值給這個(gè)組件的prop的話,那么得到的結(jié)果很有可能是違背了你初衷的。怎么說呢?因?yàn)橐坏┠氵@么做了,React在作shallow prop comparison的時(shí)候,new props都會(huì)被判斷為不等于old props的?,F(xiàn)實(shí)是,這么做恰恰會(huì)導(dǎo)致在每一次render的調(diào)用的時(shí)候生成一個(gè)新的值給這個(gè)屬性。

我們繼續(xù)拿上面的<Mouse>組件作為例子。假如<Mouse>組件繼承了React.PureComponent的話,我們的代碼應(yīng)該是像下面這樣的:

class Mouse extends React.PureComponent {
  // Same implementation as above...
}
class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>

        {/*          This is bad! The value of the `render` prop will          be different on each render.        */}
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}

在上面的代碼例子當(dāng)中,每一次<MouseTracker>組件的render方法被調(diào)用的時(shí)候,它都會(huì)生成一個(gè)新的函數(shù)實(shí)例給<Mouse>組件,作為“render”屬性的值。然而,我們之所以繼承React.PureComponent,就是想減少<Mouse>組件被渲染的次數(shù)。如此一來,<Mouse>因?yàn)橐粋€(gè)新的函數(shù)實(shí)例被判定為props已經(jīng)發(fā)生改變了,于是乎進(jìn)行了不必要的渲染。這與我們的讓<Mouse>組件繼承React.PureComponent的初衷是相違背的。

為了避開(To get around)這個(gè)問題,你可以把render prop的值賦值為<MouseTracker>組件實(shí)例的一個(gè)方法,這樣:

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>
    );
  }
}

在某些場景下,你可能無法把prop的值靜態(tài)地賦值為組件實(shí)例的某個(gè)方法(例如,你需要覆蓋組件的props值或者state值,又兩者都要覆蓋)。那么,在這種情況下,你只能老老實(shí)實(shí)地讓<Mouse>組件去繼承React.Component了。

到此這篇關(guān)于React RenderProps模式超詳細(xì)講解的文章就介紹到這了,更多相關(guān)React RenderProps內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React?中的?JS?報(bào)錯(cuò)及容錯(cuò)方案

    React?中的?JS?報(bào)錯(cuò)及容錯(cuò)方案

    這篇文章主要為大家介紹了React?中的?JS?報(bào)錯(cuò)及容錯(cuò)方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • react項(xiàng)目升級報(bào)錯(cuò),babel報(bào)錯(cuò),.babelrc配置兼容等問題及解決

    react項(xiàng)目升級報(bào)錯(cuò),babel報(bào)錯(cuò),.babelrc配置兼容等問題及解決

    這篇文章主要介紹了react項(xiàng)目升級報(bào)錯(cuò),babel報(bào)錯(cuò),.babelrc配置兼容等問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • React深入淺出分析Hooks源碼

    React深入淺出分析Hooks源碼

    在react類組件(class)寫法中,有setState和生命周期對狀態(tài)進(jìn)行管理,但是在函數(shù)組件中不存在這些,故引入hooks(版本:>=16.8),使開發(fā)者在非class的情況下使用更多react特性
    2022-11-11
  • 一文帶你掌握React類式組件中setState的應(yīng)用

    一文帶你掌握React類式組件中setState的應(yīng)用

    這篇文章主要為大家詳細(xì)介紹了介紹了React類式組件中setState的三種寫法以及簡單討論下setState?到底是同步的還是異步的,感興趣的可以了解下
    2024-02-02
  • 簡化Cocos和Native交互利器詳解

    簡化Cocos和Native交互利器詳解

    這篇文章主要為大家介紹了簡化Cocos和Native交互利器詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • React-Native做一個(gè)文本輸入框組件的實(shí)現(xiàn)代碼

    React-Native做一個(gè)文本輸入框組件的實(shí)現(xiàn)代碼

    這篇文章主要介紹了React-Native做一個(gè)文本輸入框組件的實(shí)現(xiàn)代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-08-08
  • React內(nèi)部實(shí)現(xiàn)cache方法示例詳解

    React內(nèi)部實(shí)現(xiàn)cache方法示例詳解

    這篇文章主要為大家介紹了React內(nèi)部實(shí)現(xiàn)cache方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • 手把手帶你用React擼一個(gè)日程組件

    手把手帶你用React擼一個(gè)日程組件

    這篇文章主要給大家介紹了關(guān)于利用React擼一個(gè)日程組件的相關(guān)資料,包括日常組件的實(shí)現(xiàn)思路、使用的技術(shù)、以及遇到的技術(shù)難點(diǎn),并給提供了詳細(xì)的實(shí)例代碼,需要的朋友可以參考下
    2021-07-07
  • React如何創(chuàng)建組件

    React如何創(chuàng)建組件

    本文我們將介紹 React中組件的類別,以及如何創(chuàng)建和使用組件。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 淺談react useEffect閉包的坑

    淺談react useEffect閉包的坑

    筆者最近用react useEffect閉包,其中踩到了一些坑在此與大家分享一下。需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06

最新評論