日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

react实现汉堡_利用 React 高阶组件实现一个面包屑导航

發(fā)布時(shí)間:2024/1/23 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 react实现汉堡_利用 React 高阶组件实现一个面包屑导航 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是 React 高階組件

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

使用 React 高階組件的好處

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

自己動(dòng)手實(shí)現(xiàn)一個(gè)高階組件

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

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

// 這里展示的是 react-router4 的route示例

let routes = [

{

breadcrumb: '一級(jí)目錄',

path: '/a',

component: require('../a/index.js').default,

items: [

{

breadcrumb: '二級(jí)目錄',

path: '/a/b',

component: require('../a/b/index.js').default,

items: [

{

breadcrumb: '三級(jí)目錄1',

path: '/a/b/c1',

component: require('../a/b/c1/index.js').default,

exact: true,

},

{

breadcrumb: '三級(jí)目錄2',

path: '/a/b/c2',

component: require('../a/b/c2/index.js').default,

exact: true,

},

}

]

}

]

// 理想中的面包屑組件

// 展示格式為 a / b / c1 并都附上鏈接

const BreadcrumbsComponent = ({ breadcrumbs }) => (

{breadcrumbs.map((breadcrumb, index) => (

{breadcrumb}

{index < breadcrumbs.length - 1 && / }

))}

);

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

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

后兩種需要我們對(duì) routes 進(jìn)行操作,首先將 routes 提供的數(shù)據(jù)扁平化成面包屑導(dǎo)航需要的格式,我們可以使用一個(gè)函數(shù)來(lái)實(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

);

}, []);

之后將展平的目錄路徑映射與當(dāng)前頁(yè)面路徑一同放入處理函數(shù),生成面包屑導(dǎo)航結(jié)構(gòu)。

export const getBreadcrumbs = ({ flattenRoutes, location }) => {

// 初始化匹配數(shù)組match

let matches = [];

location.pathname

// 取得路徑名,然后將路徑分割成每一路由部分.

.split('?')[0]

.split('/')

// 對(duì)每一部分執(zhí)行一次調(diào)用`getBreadcrumb()`的reduce.

.reduce((prev, curSection) => {

// 將最后一個(gè)路由部分與當(dāng)前部分合并,比如當(dāng)路徑為 `/x/xx/xxx` 時(shí),pathSection分別檢查 `/x` `/x/xx` `/x/xx/xxx` 的匹配,并分別生成面包屑

const pathSection = `${prev}/${curSection}`;

const breadcrumb = getBreadcrumb({

flattenRoutes,

curSection,

pathSection,

});

// 將面包屑導(dǎo)入到matches數(shù)組中

matches.push(breadcrumb);

// 傳遞給下一次reduce的路徑部分

return pathSection;

});

return matches;

};

然后對(duì)于每一個(gè)面包屑路徑部分,生成目錄名稱(chēng)并附上指向?qū)?yīng)路由位置的鏈接屬性。

const getBreadcrumb = ({ flattenRoutes, curSection, pathSection }) => {

const matchRoute = flattenRoutes.find(ele => {

const { breadcrumb, path } = ele;

if (!breadcrumb || !path) {

throw new Error(

'Router中的每一個(gè)route必須包含 `path` 以及 `breadcrumb` 屬性'

);

}

// 查找是否有匹配

// exact 為 react router4 的屬性,用于精確匹配路由

return matchPath(pathSection, { path, exact: true });

});

// 返回breadcrumb的值,沒(méi)有就返回原匹配子路徑名

if (matchRoute) {

return render({

content: matchRoute.breadcrumb || curSection,

path: matchRoute.path,

});

}

// 對(duì)于routes表中不存在的路徑

// 根目錄默認(rèn)名稱(chēng)為首頁(yè).

return render({

content: pathSection === '/' ? '首頁(yè)' : curSection,

path: pathSection,

});

};

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

/**

*

*/

const render = ({ content, path }) => {

const componentProps = { path };

if (typeof content === 'function') {

return ;

}

return {content};

};

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

const BreadcrumbsHoc = (

location = window.location,

routes = []

) => Component => {

const BreadComponent = (

breadcrumbs={getBreadcrumbs({

flattenRoutes: flattenRoutes(routes),

location,

})}

/>

);

return BreadComponent;

};

export default BreadcrumbsHoc;

調(diào)用這個(gè)高階組件的方法也非常簡(jiǎn)單,只需要傳入當(dāng)前所在路徑以及整個(gè) react router 生成的 routes 屬性即可。

至于如何取得當(dāng)前所在路徑,我們可以利用 react router 提供的 withRouter 函數(shù),如何使用請(qǐng)自行查閱相關(guān)文檔。

值得一提的是,withRouter 本身就是一個(gè)高階組件,能為包裹組件提供包括 location 屬性在內(nèi)的若干路由屬性。所以這個(gè) API 也能作為學(xué)習(xí)高階組件一個(gè)很好的參考。

withRouter(({ location }) =>

BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)

);

4. Q&A

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

function mapStateToProps(state) {

return {

routes: state.routes,

};

}

connect(mapStateToProps)(

withRouter(({ location }) =>

BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)

)

);

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

官方推薦的做法是使用 withRouter 來(lái)包裹 connect 的 return value,即

withRouter(

connect(mapStateToProps)(({ location, routes }) =>

BreadcrumbsHoc(location, routes)(BreadcrumbsComponent)

)

);

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

總結(jié)

以上是生活随笔為你收集整理的react实现汉堡_利用 React 高阶组件实现一个面包屑导航的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。