Skip to content

Commit 53dacc0

Browse files
authored
Support React Router v6 (#32)
* feat: support react-router-v6 * feat: support react-router-v6 * style: fix code style * chore: update README * chore: release v3.0.0
1 parent ee9c360 commit 53dacc0

File tree

5 files changed

+451
-291
lines changed

5 files changed

+451
-291
lines changed

README.md

Lines changed: 71 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Render breadcrumbs for `react-router` however you want!
5151
#### Features
5252
- Easy to get started with automatically generated breadcrumbs.
5353
- Render, map, and wrap breadcrumbs any way you want.
54-
- Compatible with existing [route configs](https://reacttraining.com/react-router/web/example/route-config).
54+
- Compatible with existing [route objects](https://reactrouter.com/docs/en/v6/examples/route-objects).
5555

5656
## Install
5757

@@ -114,8 +114,8 @@ const Breadcrumbs = () => {
114114
match,
115115
breadcrumb
116116
}) => (
117-
<span key={match.url}>
118-
<NavLink to={match.url}>{breadcrumb}</NavLink>
117+
<span key={match.pathname}>
118+
<NavLink to={match.pathname}>{breadcrumb}</NavLink>
119119
</span>
120120
))}
121121
</>
@@ -131,44 +131,44 @@ Pathname | Result
131131
/users/1 | Home / Users / John
132132
/example | Home / Custom Example
133133

134-
## [Route config](https://reacttraining.com/react-router/web/example/route-config) compatibility
134+
## [Route object](https://reactrouter.com/docs/en/v6/examples/route-objects) compatibility
135135

136-
Add breadcrumbs to your existing [route config](https://reacttraining.com/react-router/web/example/route-config). This is a great way to keep all routing config paths in a single place! If a path ever changes, you'll only have to change it in your main route config rather than maintaining a _separate_ config for `use-react-router-breadcrumbs`.
136+
Add breadcrumbs to your existing [route object](https://reactrouter.com/docs/en/v6/examples/route-objects). This is a great way to keep all routing config paths in a single place! If a path ever changes, you'll only have to change it in your main route config rather than maintaining a _separate_ config for `use-react-router-breadcrumbs`.
137137

138138
For example...
139139

140140
```js
141-
const routeConfig = [
141+
const routes = [
142142
{
143143
path: "/sandwiches",
144-
component: Sandwiches
144+
element: <Sandwiches />
145145
}
146146
];
147147
```
148148

149149
becomes...
150150

151151
```js
152-
const routeConfig = [
152+
const routes = [
153153
{
154154
path: "/sandwiches",
155-
component: Sandwiches,
155+
element: <Sandwiches />,
156156
breadcrumb: 'I love sandwiches'
157157
}
158158
];
159159
```
160160

161-
then you can just pass the whole route config right into the hook:
161+
then you can just pass the whole routes right into the hook:
162162

163163
```js
164-
const breadcrumbs = useBreadcrumbs(routeConfig);
164+
const breadcrumbs = useBreadcrumbs(routes);
165165
```
166166

167167
## Dynamic breadcrumb components
168168

169-
If you pass a component as the `breadcrumb` prop it will be injected with react-router's [match](https://reacttraining.com/react-router/web/api/match) and [location](https://reacttraining.com/react-router/web/api/location) objects as props. These objects contain ids, hashes, queries, etc... from the route that will allow you to map back to whatever you want to display in the breadcrumb.
169+
If you pass a component as the `breadcrumb` prop it will be injected with react-router's [match](https://reactrouter.com/docs/en/v6/api#matchpath) and [location](https://reactrouter.com/docs/en/v6/api#location) objects as props. These objects contain ids, hashes, queries, etc... from the route that will allow you to map back to whatever you want to display in the breadcrumb.
170170

171-
Let's use `redux` as an example with the [match](https://reacttraining.com/react-router/web/api/match) object:
171+
Let's use `redux` as an example with the [match](https://reactrouter.com/docs/en/v6/api#matchpath) object:
172172

173173
```js
174174
// UserBreadcrumb.jsx
@@ -194,9 +194,19 @@ const breadcrumbs = useBreadcrumbs([{
194194
}]);
195195
```
196196

197+
You cannot use hooks that rely on `RouteContext` like `useParams`, because the breadcrumbs are not in the context, you should use `match.params` instead:
198+
199+
```tsx
200+
import type { BreadcrumbComponentType } from 'use-react-router-breadcrumbs';
201+
202+
const UserBreadcrumb: BreadcrumbComponentType<'id'> = ({ match }) => {
203+
return <div>{match.params.id}</div>;
204+
}
205+
```
206+
197207
----
198208

199-
Similarly, the [location](https://reacttraining.com/react-router/web/api/location) object could be useful for displaying dynamic breadcrumbs based on the route's state:
209+
Similarly, the [location](https://reactrouter.com/docs/en/v6/api#location) object could be useful for displaying dynamic breadcrumbs based on the route's state:
200210

201211
```jsx
202212
// dynamically update EditorBreadcrumb based on state info
@@ -250,53 +260,76 @@ useBreadcrumbs(routes, { excludePaths: ['/', '/no-breadcrumb/for-this-route'] })
250260

251261
## Order matters!
252262

263+
`use-react-router-breadcrumbs` uses the same strategy as `React Router v6` to calculate the routing order.
264+
253265
... in certain cases. Consider the following:
254266

255267
```js
256268
[
257-
{ path: '/users/:id', breadcrumb: 'id-breadcrumb' },
258-
{ path: '/users/create', breadcrumb: 'create-breadcrumb' },
269+
{
270+
path: 'users',
271+
children: [
272+
{ path: ':id', breadcrumb: 'id-breadcrumb' },
273+
{ path: 'create', breadcrumb: 'create-breadcrumb' },
274+
],
275+
},
259276
]
260277
```
261278

262-
If the user visits `example.com/users/create` they will see `id-breadcrumb` because `/users/:id` will match _before_ `/users/create`.
279+
If the user visits `example.com/users/create` they will see `create-breadcrumb`.
263280

264-
To fix the issue above, just adjust the order of your routes:
281+
In addition, if the index route and the parent route provide breadcrumb at the same time, the index route provided will be used first:
265282

266283
```js
267284
[
268-
{ path: '/users/create', breadcrumb: 'create-breadcrumb' },
269-
{ path: '/users/:id', breadcrumb: 'id-breadcrumb' },
285+
{
286+
path: 'users',
287+
breadcrumb: 'parent-breadcrumb',
288+
children: [
289+
{ index: true, breadcrumb: 'child-breadcrumb' },
290+
],
291+
},
270292
]
271293
```
272294

273-
Now, `example.com/users/create` will display `create-breadcrumb` as expected, because it will match first before the `/users/:id` route.
295+
If the user visits `example.com/users` they will see `child-breadcrumb`.
274296

275297
## API
276298

277-
```js
278-
BreadcrumbsRoute = {
279-
path: String
280-
breadcrumb?: React.ComponentType | React.ElementType | string | null
281-
// see: https://reacttraining.com/react-router/web/api/matchPath
282-
matchOptions?: {
283-
exact?: boolean
284-
strict?: boolean
285-
sensitive?: boolean
286-
}
287-
// optional nested routes (for react-router config compatibility)
288-
routes?: BreadcrumbsRoute[],
289-
// optional props to be passed through directly to the breadcrumb component
299+
```ts
300+
interface BreadcrumbComponentProps<ParamKey extends string = string> {
301+
key: string;
302+
match: BreadcrumbMatch<ParamKey>;
303+
location: Location;
304+
}
305+
306+
type BreadcrumbComponentType<ParamKey extends string = string> =
307+
React.ComponentType<BreadcrumbComponentProps<ParamKey>>;
308+
309+
interface BreadcrumbsRoute<ParamKey extends string = string>
310+
extends RouteObject {
311+
children?: BreadcrumbsRoute[];
312+
breadcrumb?: BreadcrumbComponentType<ParamKey> | string | null;
290313
props?: { [x: string]: unknown };
291314
}
292315

293-
Options = {
316+
interface Options {
294317
// disable all default generation of breadcrumbs
295-
disableDefaults?: boolean
318+
disableDefaults?: boolean;
296319
// exclude certain paths fom generating breadcrumbs
297-
excludePaths?: string[]
320+
excludePaths?: string[];
321+
}
322+
323+
interface BreadcrumbData<ParamKey extends string = string> {
324+
match: BreadcrumbMatch<ParamKey>;
325+
location: Location;
326+
key: string;
327+
breadcrumb: React.ReactNode;
298328
}
299329

300330
// if routes are not passed, default breadcrumbs will be returned
301-
useBreadcrumbs(routes?: BreadcrumbsRoute[], options?: Options): Array<React.node>
331+
function useBreadcrumbs(
332+
routes?: BreadcrumbsRoute[],
333+
options?: Options
334+
): BreadcrumbData[];
302335
```

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "use-react-router-breadcrumbs",
3-
"version": "2.0.2",
3+
"version": "3.0.0",
44
"description": "A hook for displaying and setting breadcrumbs for react router",
55
"main": "dist/cjs/index.js",
66
"module": "dist/es/index.js",
@@ -11,7 +11,7 @@
1111
"types": "dist/index.d.ts",
1212
"peerDependencies": {
1313
"react": ">=16.8",
14-
"react-router": ">=5.1.0"
14+
"react-router": ">=6.0.0"
1515
},
1616
"scripts": {
1717
"prepublishOnly": "yarn build && pinst --disable",
@@ -36,7 +36,6 @@
3636
"@rollup/plugin-typescript": "^8.2.1",
3737
"@types/react": "^17.0.11",
3838
"@types/react-dom": "^17.0.7",
39-
"@types/react-router": "^5.1.15",
4039
"@typescript-eslint/eslint-plugin": "^4.26.1",
4140
"@typescript-eslint/parser": "^4.26.1",
4241
"@wojtekmaj/enzyme-adapter-react-17": "^0.6.1",
@@ -55,7 +54,7 @@
5554
"prop-types": "^15.7.2",
5655
"react": "^17.0.2",
5756
"react-dom": "^17.0.2",
58-
"react-router": "^5.2.0",
57+
"react-router": "^6.0.0",
5958
"rollup": "^2.51.1",
6059
"rollup-plugin-size": "^0.2.2",
6160
"rollup-plugin-terser": "^7.0.2",
@@ -66,6 +65,6 @@
6665
"router",
6766
"breadcrumbs",
6867
"react-router",
69-
"react-router 5"
68+
"react-router 6"
7069
]
7170
}

0 commit comments

Comments
 (0)