最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

利用React高階組件實現(xiàn)一個面包屑導航的示例

 更新時間:2020年08月23日 16:00:27   作者:Duang  
這篇文章主要介紹了利用React高階組件實現(xiàn)一個面包屑導航的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

什么是 React 高階組件

React 高階組件就是以高階函數(shù)的方式包裹需要修飾的 React 組件,并返回處理完成后的 React 組件。React 高階組件在 React 生態(tài)中使用的非常頻繁,比如react-router 中的 withRouter 以及 react-redux 中 connect 等許多 API 都是以這樣的方式來實現(xiàn)的。

使用 React 高階組件的好處

在工作中,我們經(jīng)常會有很多功能相似,組件代碼重復的頁面需求,通常我們可以通過完全復制一遍代碼的方式實現(xiàn)功能,但是這樣頁面的維護可維護性就會變得極差,需要對每一個頁面里的相同組件去做更改。因此,我們可以將其中共同的部分,比如接受相同的查詢操作結果、組件外同一的標簽包裹等抽離出來,做一個單獨的函數(shù),并傳入不同的業(yè)務組件作為子組件參數(shù),而這個函數(shù)不會修改子組件,只是通過組合的方式將子組件包裝在容器組件中,是一個無副作用的純函數(shù),從而我們能夠在不改變這些組件邏輯的情況下將這部分代碼解耦,提升代碼可維護性。

自己動手實現(xiàn)一個高階組件

前端項目里,帶鏈接指向的面包屑導航十分常用,但由于面包屑導航需要手動維護一個所有目錄路徑與目錄名映射的數(shù)組,而這里所有的數(shù)據(jù)我們都能從 react-router 的路由表中取得,因此我們可以從這里入手,實現(xiàn)一個面包屑導航的高階組件。

首先我們看看我們的路由表提供的數(shù)據(jù)以及目標面包屑組件所需要的數(shù)據(jù):

// 這里展示的是 react-router4 的route示例
let routes = [
 {
  breadcrumb: '一級目錄',
  path: '/a',
  component: require('../a/index.js').default,
  items: [
   {
    breadcrumb: '二級目錄',
    path: '/a/b',
    component: require('../a/b/index.js').default,
    items: [
     {
      breadcrumb: '三級目錄1',
      path: '/a/b/c1',
      component: require('../a/b/c1/index.js').default,
      exact: true,
     },
     {
      breadcrumb: '三級目錄2',
      path: '/a/b/c2',
      component: require('../a/b/c2/index.js').default,
      exact: true,
     },
   }
  ]
 }
]

// 理想中的面包屑組件
// 展示格式為 a / b / c1 并都附上鏈接
const BreadcrumbsComponent = ({ breadcrumbs }) => (
 <div>
  {breadcrumbs.map((breadcrumb, index) => (
   <span key={breadcrumb.props.path}>
    <link to={breadcrumb.props.path}>{breadcrumb}</link>
    {index < breadcrumbs.length - 1 && <i> / </i>}
   </span>
  ))}
 </div>
);

這里我們可以看到,面包屑組件需要提供的數(shù)據(jù)一共有三種,一種是當前頁面的路徑,一種是面包屑所帶的文字,一種是該面包屑的導航鏈接指向。

其中第一種我們可以通過 react-router 提供的 withRouter 高階組件包裹,可使子組件獲取到當前頁面的 location 屬性,從而獲取頁面路徑。

后兩種需要我們對 routes 進行操作,首先將 routes 提供的數(shù)據(jù)扁平化成面包屑導航需要的格式,我們可以使用一個函數(shù)來實現(xiàn)它。

/**
 * 以遞歸的方式展平react router數(shù)組
 */
const flattenRoutes = arr =>
 arr.reduce(function(prev, item) {
  prev.push(item);
  return prev.concat(
   Array.isArray(item.items) ? flattenRoutes(item.items) : item
  );
 }, []);

之后將展平的目錄路徑映射與當前頁面路徑一同放入處理函數(shù),生成面包屑導航結構。

export const getBreadcrumbs = ({ flattenRoutes, location }) => {
 // 初始化匹配數(shù)組match
 let matches = [];

 location.pathname
  // 取得路徑名,然后將路徑分割成每一路由部分.
  .split('?')[0]
  .split('/')
  // 對每一部分執(zhí)行一次調用`getBreadcrumb()`的reduce.
  .reduce((prev, curSection) => {
   // 將最后一個路由部分與當前部分合并,比如當路徑為 `/x/xx/xxx` 時,pathSection分別檢查 `/x` `/x/xx` `/x/xx/xxx` 的匹配,并分別生成面包屑
   const pathSection = `${prev}/${curSection}`;
   const breadcrumb = getBreadcrumb({
    flattenRoutes,
    curSection,
    pathSection,
   });

   // 將面包屑導入到matches數(shù)組中
   matches.push(breadcrumb);

   // 傳遞給下一次reduce的路徑部分
   return pathSection;
  });
 return matches;
};

然后對于每一個面包屑路徑部分,生成目錄名稱并附上指向對應路由位置的鏈接屬性。

const getBreadcrumb = ({ flattenRoutes, curSection, pathSection }) => {
 const matchRoute = flattenRoutes.find(ele => {
  const { breadcrumb, path } = ele;
  if (!breadcrumb || !path) {
   throw new Error(
    'Router中的每一個route必須包含 `path` 以及 `breadcrumb` 屬性'
   );
  }
  // 查找是否有匹配
  // exact 為 react router4 的屬性,用于精確匹配路由
  return matchPath(pathSection, { path, exact: true });
 });

 // 返回breadcrumb的值,沒有就返回原匹配子路徑名
 if (matchRoute) {
  return render({
   content: matchRoute.breadcrumb || curSection,
   path: matchRoute.path,
  });
 }

 // 對于routes表中不存在的路徑
 // 根目錄默認名稱為首頁.
 return render({
  content: pathSection === '/' ? '首頁' : curSection,
  path: pathSection,
 });
};

之后由 render 函數(shù)生成最后的單個面包屑導航樣式。單個面包屑組件需要為 render 函數(shù)提供該面包屑指向的路徑 path, 以及該面包屑內容映射content 這兩個 props。

/**
 *
 */
const render = ({ content, path }) => {
 const componentProps = { path };
 if (typeof content === 'function') {
  return <content {...componentProps} />;
 }
 return <span {...componentProps}>{content}</span>;
};

有了這些功能函數(shù),我們就能實現(xiàn)一個能為包裹組件傳入當前所在路徑以及路由屬性的 React 高階組件了。傳入一個組件,返回一個新的相同的組件結構,這樣便不會對組件外的任何功能與操作造成破壞。

const BreadcrumbsHoc = (
 location = window.location,
 routes = []
) => Component => {
 const BreadComponent = (
  <Component
   breadcrumbs={getBreadcrumbs({
    flattenRoutes: flattenRoutes(routes),
    location,
   })}
  />
 );
 return BreadComponent;
};
export default BreadcrumbsHoc;

調用這個高階組件的方法也非常簡單,只需要傳入當前所在路徑以及整個 react router 生成的 routes 屬性即可。
至于如何取得當前所在路徑,我們可以利用 react router 提供的 withRouter 函數(shù),如何使用請自行查閱相關文檔。
值得一提的是,withRouter 本身就是一個高階組件,能為包裹組件提供包括 location 屬性在內的若干路由屬性。所以這個 API 也能作為學習高階組件一個很好的參考。

withRouter(({ location }) =>
 BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)
);

Q&A

如果react router 生成的 routes 不是由自己手動維護的,甚至都沒有存在本地,而是通過請求拉取到的,存儲在 redux 里,通過 react-redux 提供的 connect 高階函數(shù)包裹時,路由發(fā)生變化時并不會導致該面包屑組件更新。使用方法如下:

function mapStateToProps(state) {
 return {
  routes: state.routes,
 };
}

connect(mapStateToProps)(
 withRouter(({ location }) =>
  BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)
 )
);

這其實是 connect 函數(shù)的一個bug。因為 react-redux 的 connect 高階組件會為傳入的參數(shù)組件實現(xiàn) shouldComponentUpdate 這個鉤子函數(shù),導致只有 prop 發(fā)生變化時才觸發(fā)更新相關的生命周期函數(shù)(含 render),而很顯然,我們的 location 對象并沒有作為 prop 傳入該參數(shù)組件。

官方推薦的做法是使用 withRouter 來包裹 connect 的 return value,即

withRouter(
 connect(mapStateToProps)(({ location, routes }) =>
  BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)
 )
);

其實我們從這里也可以看出,高階組件同高階函數(shù)一樣,不會對組件的類型造成任何更改,因此高階組件就如同鏈式調用一樣,可以任意多層包裹來給組件傳入不同的屬性,在正常情況下也可以隨意調換位置,在使用上非常的靈活。這種可插拔特性使得高階組件非常受 React 生態(tài)的青睞,很多開源庫里都能看到這種特性的影子,有空也可以都拿出來分析一下。

到此這篇關于利用React高階組件實現(xiàn)一個面包屑導航的示例的文章就介紹到這了,更多相關React 面包屑導航內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • React狀態(tài)管理Redux的使用介紹詳解

    React狀態(tài)管理Redux的使用介紹詳解

    redux是redux官方react綁定庫,能夠使react組件從redux store中讀取數(shù)據(jù),并且向store分發(fā)actions以此來更新數(shù)據(jù),這篇文章主要介紹了react-redux的設置,需要的朋友可以參考下
    2022-09-09
  • 簡單分析React中的EffectList

    簡單分析React中的EffectList

    這篇文章主要簡單分析了React中的EffectList,幫助大家更好的理解和學習使用React進行前端開發(fā),感興趣的朋友可以了解下
    2021-04-04
  • react嵌套路由實現(xiàn)TabBar的實現(xiàn)

    react嵌套路由實現(xiàn)TabBar的實現(xiàn)

    本文主要介紹了react嵌套路由實現(xiàn)TabBar的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • 解析React?ref?命令代替父子組件的數(shù)據(jù)傳遞問題

    解析React?ref?命令代替父子組件的數(shù)據(jù)傳遞問題

    這篇文章主要介紹了React?-?ref?命令為什么代替父子組件的數(shù)據(jù)傳遞,使用?ref?之后,我們不需要再進行頻繁的父子傳遞了,子組件也可以有自己的私有狀態(tài)并且不會影響信息的正常需求,這是為什么呢?因為我們使用了?ref?命令的話,ref是可以進行狀態(tài)的傳輸
    2022-08-08
  • React?less?實現(xiàn)縱橫柱狀圖示例詳解

    React?less?實現(xiàn)縱橫柱狀圖示例詳解

    這篇文章主要介紹了React?less?實現(xiàn)縱橫柱狀圖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • 在React項目中使用Eslint代碼檢查工具及常見問題

    在React項目中使用Eslint代碼檢查工具及常見問題

    這篇文章主要介紹了在React項目中使用Eslint代碼檢查工具及常見問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-10-10
  • React實現(xiàn)歌詞滾動效果(跟隨音樂播放時間滾動)

    React實現(xiàn)歌詞滾動效果(跟隨音樂播放時間滾動)

    這篇文章主要為大家詳細介紹了React實現(xiàn)歌詞滾動效果(跟隨音樂播放使勁按滾動),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2024-02-02
  • React配置Redux并結合本地存儲設置token方式

    React配置Redux并結合本地存儲設置token方式

    這篇文章主要介紹了React配置Redux并結合本地存儲設置token方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • useReducer使用詳解及其應用場景

    useReducer使用詳解及其應用場景

    這篇文章主要介紹了useReducer使用詳解及其應用場景,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • React復制到剪貼板的示例代碼

    React復制到剪貼板的示例代碼

    本篇文章主要介紹了React復制到剪貼板的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08

最新評論

红桥区| 宁蒗| 乡宁县| 阳西县| 博爱县| 南昌市| 阿克陶县| 沈丘县| 廊坊市| 洛隆县| 东乌珠穆沁旗| 阳山县| 东方市| 潼南县| 合作市| 图们市| 徐州市| 平陆县| 安徽省| 九龙县| 华蓥市| 青海省| 汾阳市| 大悟县| 辉南县| 无为县| 三都| 阳东县| 丹寨县| 伊春市| 邯郸县| 信阳市| 上杭县| 大田县| 台北市| 澄迈县| 平阴县| 凌云县| 泾阳县| 揭阳市| 左云县|