亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

通過實例了解Render Props回調地獄解決方案

 更新時間:2020年11月04日 15:22:27   作者:酷兒q  
這篇文章主要介紹了通過實例了解Render Props回調地獄解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

簡而言之,只要一個組件中某個屬性的值是函數,那么就可以說該組件使用了 Render Props 這種技術。聽起來好像就那么回事兒,那到底 Render Props 有哪些應用場景呢,咱們還是從簡單的例子講起,假如咱們要實現一個展示個人信息的組件,一開始可能會這么實現:

const PersonInfo = props => (
 <div>
  <h1>姓名:{props.name}</h1>
 </div>
);
// 調用
<PersonInfo name='web前端'/>

如果,想要在 PersonInfo 組件上還需要一個年齡呢,咱們會這么實現:

const PersonInfo = props => (
 <div>
  <h1>姓名:{props.name}</h1>
  <p>年齡:{props.age}</[>
 </div>
);

// 調用
<PersonInfo name='web前端' age='18'/>

然后如果還要加上鏈接呢,又要在 PersonInfo 組件的內部實現發(fā)送鏈接的邏輯,很明顯這種方式違背了軟件開發(fā)六大原則之一的 開閉原則,即每次修改都要到組件內部需修改。

開閉原則:對修改關閉,對拓展開放。

那有什么方法可以避免這種方式的修改呢?

在原生 js 中,如果咱們調用函數后,還要做些騷操作,咱們一般使用回調函數來處理這種情況。

在 react 中咱們可以使用 Render Props,其實和回調一樣:

const PersonInfo = props => {
return props.render(props);
}
// 使用

<PersonInfo 
 name='web前端' age = '18' link = 'link'
 render = {(props) => {
  <div>
   <h1>{props.name}</h1>
   <p>{props.age}</p>
   <a href="props.link" rel="external nofollow" ></a>
  </div>
 }}
/>

值得一提的是,并不是只有在 render 屬性中傳入函數才能叫 Render Props,實際上任何屬性只要它的值是函數,都可稱之為 Render Props,比如上面這個例子把 render 屬性名改成 children 的話使用上其實更為簡便:

const PersonInfo = props => {
  return props.children(props);
};

<PersonInfo name='web前端' age = '18' link = 'link'>
{(props) => (
  <div>
    <h1>{props.name}</h1>
    <p>{props.age}</p>
    <a href={props.link}></a>
  </div>
)}
</PersonInfo

這樣就可以直接在 PersonInfo 標簽內寫函數了,比起之前在 render 中更為直觀。

所以,React 中的 Render Props 你可以把它理解成 js 中的回調函數。

React 組件的良好設計是可維護且易于更改代碼的關鍵。

從這個意義上說,React 提供了許多設計技術,比如組合、Hooks、高階組件、Render Props等等。

Render props 可以有效地以松散耦合的方式設計組件。它的本質在于使用一個特殊的prop(通常稱為render),將渲染邏輯委托給父組件。

import Mouse from 'Mouse';
function ShowMousePosition() {
 return (
  <Mouse 
   render = {
    ({ x, y }) => <div>Position: {x}px, {y}px</div> 
   }
  />
 )
}

使用此模式時,遲早會遇到在多個 render prop 回調中嵌套組件的問題: render props 回調地獄。

1. Render Props 的回調地獄

假設各位需要檢測并顯示網站訪問者所在的城市。

首先,需要確定用戶地理坐標的組件,像<AsyncCoords render={coords => ... } 這樣的組件進行異步操作,使用 Geolocation API,然后調用Render prop 進行回調。。

然后用獲取的坐標用來近似確定用戶的城市:<AsyncCity lat={lat} long={long} render={city => ...} />,這個組件也叫Render prop。

接著咱們將這些異步組件合并到<DetectCity>組件中

function DetectCity() {
 return (
  <AsyncCoords 
   render={({ lat, long }) => {
    return (
     <AsyncCity 
      lat={lat} 
      long={long} 
      render={city => {
       if (city == null) {
        return <div>Unable to detect city.</div>;
       }
       return <div>You might be in {city}.</div>;
      }}
     />
    );
   }}
  />
 );
}
// 在某處使用
<DetectCity />

可能已經發(fā)現了這個問題:Render Prop回調函數的嵌套。嵌套的回調函數越多,代碼就越難理解。這是Render Prop回調地獄的問題。

咱們換中更好的組件設計,以排除回調的嵌套問題。

2. Class 方法

為了將回調的嵌套轉換為可讀性更好的代碼,咱們將回調重構為類的方法。

class DetectCity extends React.Component {
 render() {
  return <AsyncCoords render={this.renderCoords} />;
 }

 renderCoords = ({ lat, long }) => {
  return <AsyncCity lat={lat} long={long} render={this.renderCity}/>;
 }

 renderCity = city => {
  if (city == null) {
   return <div>Unable to detect city.</div>;
  }
  return <div>You might be in {city}.</div>;
 }
}

// 在某處使用
<DetectCity />

回調被提取到分開的方法renderCoords()和renderCity()中。這樣的組件設計更容易理解,因為渲染邏輯封裝在一個單獨的方法中。

如果需要更多嵌套,類的方式是垂直增加(通過添加新方法),而不是水平(通過相互嵌套函數),回調地獄問題消失。

2.1 訪問渲染方法內部的組件 props

方法renderCoors()和renderCity()是使用箭頭函法定義的,這樣可以將 this 綁定到組件實例,所以可以在<AsyncCoords>和<AsyncCity>組件中調用這些方法。

有了this作為組件實例,就可以通過 prop 獲取所需要的內容:

class DetectCityMessage extends React.Component {
 render() {
  return <AsyncCoords render={this.renderCoords} />;
 }

 renderCoords = ({ lat, long }) => {
  return <AsyncCity lat={lat} long={long} render={this.renderCity}/>;
 }

 renderCity = city => {
  // 看這
  const { noCityMessage } = this.props;
  if (city == null) {
   return <div>{noCityMessage}</div>;
  }
  return <div>You might be in {city}.</div>;
 }
}
<DetectCityMessage noCityMessage="Unable to detect city." />

renderCity()中的this值指向<DetectCityMessage>組件實例?,F在就很容易從this.props獲取 noCityMessage 的值 。

3. 函數組合方法

如果咱們想要一個不涉及創(chuàng)建類的更輕松的方法,可以簡單地使用函數組合。

使用函數組合重構 DetectCity 組件:

function DetectCity() {
 return <AsyncCoords render={renderCoords} />;
}

function renderCoords({ lat, long }) {
 return <AsyncCity lat={lat} long={long} render={renderCity}/>;
}

function renderCity(city) {
 if (city == null) {
  return <div>Unable to detect city.</div>;
 }
 return <div>You might be in {city}.</div>;
}

// Somewhere
<DetectCity />

現在,常規(guī)函數renderCoors()和renderCity()封裝了渲染邏輯,而不是用方法創(chuàng)建類。

如果需要更多嵌套,只需要再次添加新函數即可。代碼垂直增長(通過添加新函數),而不是水平增長(通過嵌套),從而解決回調地獄問題。

這種方法的另一個好處是可以單獨測試渲染函數:renderCoords()和renderCity()。

3.1 訪問渲染函數內部組件的 prop

如果需要訪問渲染函數中的 prop ,可以直接將渲染函數插入組件中

function DetectCityMessage(props) {
 return (
  <AsyncCoords 
   render={renderCoords} 
  />
 );

 function renderCoords({ lat, long }) {
  return (
   <AsyncCity 
    lat={lat} 
    long={long} 
    render={renderCity}
   />
  );
 }

 function renderCity(city) {
  const { noCityMessage } = props;
  if (city == null) {
   return <div>{noCityMessage}</div>;
  }
  return <div>You might be in {city}.</div>;
 }
}

// Somewhere
<DetectCityMessage noCityMessage="Unknown city." />

雖然這種結構有效,但我不太喜歡它,因為每次<DetectCityMessage>重新渲染時,都會創(chuàng)建renderCoords()和renderCity()的新函數實例。

前面提到的類方法可能更適合使用。同時,這些方法不會在每次重新渲染時重新創(chuàng)建。

4. 實用的方法

如果想要在如何處理render props回調方面具有更大的靈活性,那么使用React-adopt是一個不錯的選擇。

使用 react-adopt 來重構 <DetectCity> 組件:

import { adopt } from 'react-adopt';

const Composed = adopt({
 coords: ({ render }) => <AsyncCoords render={render} />,
 city: ({ coords: { lat, long }, render }) => (
  <AsyncCity lat={lat} long={long} render={render} />
 )
});

function DetectCity() {
 return (
  <Composed>
   { city => {
    if (city == null) {
     return <div>Unable to detect city.</div>;
    }
    return <div>You might be in {city}.</div>;
   }}
  </Composed>
 );
}
<DetectCity />

react-adopt需要一個特殊的映射器來描述異步操作的順序。同時,庫負責創(chuàng)建定制的渲染回調,以確保正確的異步執(zhí)行順序。

你可能會注意到的,上面使用react-adopt 的示例比使用類組件或函數組合的方法需要更多的代碼。那么,為什么還要使用“react-adopt”呢?

不幸的是,如果需要聚合多個render props的結果,那么類組件和函數組合方法并不合適。

4.1 聚合多個渲染道具結果

想象一下,當咱們渲染3個render prop回調的結果時(AsyncFetch1、AsyncFetch2、AsyncFetch3)

function MultipleFetchResult() {
 return (
  <AsyncFetch1 render={result1 => (
   <AsyncFetch2 render={result2 => (
    <AsyncFetch3 render={result3 => (
     <span>
      Fetch result 1: {result1}
      Fetch result 2: {result2}
      Fetch result 3: {result3}
     </span>
    )} />
   )} />
  )} />
 );
}
<MultipleFetchResult />

<MultipleFetchResult>組件沉浸所有3個異步獲取操作的結果,這是一個闊怕回調地獄的情況。

如果嘗試使用類組件或函數的組合方法,它會很麻煩。 回調地獄轉變?yōu)閰到壎ǖ鬲z:

class MultipleFetchResult extends React.Component {
 render() {
  return <AsyncFetch1 render={this.renderResult1} />;
 }

 renderResult1(result1) {
  return (
   <AsyncFetch2 
    render={this.renderResult2.bind(this, result1)} 
   />
  );
 }

 renderResult2(result1, result2) {
  return (
   <AsyncFetch2 
    render={this.renderResult3.bind(this, result1, result2)}
   />
  );
 }

 renderResult3(result1, result2, result3) {
  return (
   <span>
    Fetch result 1: {result1}
    Fetch result 2: {result2}
    Fetch result 3: {result3}
   </span>
  );
 }
}
// Somewhere
<MultipleFetchResult />

咱們必須手動綁定render prop回調的結果,直到它們最終到達renderResult3()方法。

如果不喜歡手工綁定,那么采用react-adopt可能會更好:

mport { adopt } from 'react-adopt';
const Composed = adopt({
 result1: ({ render }) => <AsyncFetch1 render={render} />,
 result2: ({ render }) => <AsyncFetch2 render={render} />,
 result3: ({ render }) => <AsyncFetch3 render={render} />
});
function MultipleFetchResult() {
 return (
  <Composed>
   {({ result1, result2, result3 }) => (
    <span>
     Fetch result 1: {result1}
     Fetch result 2: {result2}
     Fetch result 3: {result3}
    </span>
   )}
  </Composed>
 );
}

// Somewhere
<MultipleFetchResult />

在函數({result1, result2, result3}) =>{…}提供給<Composed>。因此,咱們不必手動綁定參數或嵌套回調。

當然,react-adopt的代價是要學習額外的抽象,并略微增加應用程序的大小。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 代碼生成器 document.write()

    代碼生成器 document.write()

    代碼生成器 document.write()...
    2007-04-04
  • javascript常見數字進制轉換實例分析

    javascript常見數字進制轉換實例分析

    這篇文章主要介紹了javascript常見數字進制轉換,結合實例形式分析了JavaScript十進制,十六進制及二進制的相互轉換原理與技巧,需要的朋友可以參考下
    2016-04-04
  • 防止頁面url緩存中ajax中post請求的處理方法

    防止頁面url緩存中ajax中post請求的處理方法

    這篇文章主要介紹了防止頁面url緩存中ajax中post請求的處理方式的相關資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • 微信小程序實現發(fā)紅包功能

    微信小程序實現發(fā)紅包功能

    這篇文章主要為大家詳細介紹了微信小程序實現發(fā)紅包功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • layui實現根據table數據判斷按鈕顯示情況的方法

    layui實現根據table數據判斷按鈕顯示情況的方法

    今天小編就為大家分享一篇layui實現根據table數據判斷按鈕顯示情況的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-09-09
  • 深入理解TypeScript 類型兼容性

    深入理解TypeScript 類型兼容性

    本文主要介紹了TypeScript 在函數、枚舉、類和泛型中的類型兼容性規(guī)則,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-01-01
  • js原生瀑布流插件制作

    js原生瀑布流插件制作

    這篇文章主要為大家詳細介紹了js原生瀑布流插件制作,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Javascript中的for in循環(huán)和hasOwnProperty結合使用

    Javascript中的for in循環(huán)和hasOwnProperty結合使用

    當檢測某個對象是否擁有某個屬性時,hasOwnProperty 是唯一可以完成這一任務的方法,在 for in 循環(huán)時,建議增加 hasOwnProperty 進行判斷,可以有效避免擴展本地原型而引起的錯誤
    2013-06-06
  • Bootstrap按鈕組件詳解

    Bootstrap按鈕組件詳解

    按鈕組和下拉菜單組件一樣,需要依賴于button.js插件才能正常運作。通過本文給大家詳細介紹Bootstrap按鈕組件,感興趣的朋友一起學習吧
    2016-04-04
  • javascript對象的創(chuàng)建和訪問

    javascript對象的創(chuàng)建和訪問

    這篇文章主要為大家詳細介紹了javascript對象的創(chuàng)建和訪問實現方法,感興趣的小伙伴們可以參考一下
    2016-03-03

最新評論