React Router v6
Learn about Sentry's React Router v6 integration.
- React Router v6 support is included in the
@sentry/react
package since version7
.
Update your Sentry.browserTracingIntegration
to Sentry.reactRouterV6BrowserTracingIntegration
and provide the required React hooks and router functions:
useEffect
hook fromreact
useLocation
anduseNavigationType
hooks fromreact-router-dom
orreact-router
createRoutesFromChildren
andmatchRoutes
functions fromreact-router-dom
orreact-router
To ensure proper routing instrumentation, initialize Sentry by calling Sentry.init
before:
- Wrapping your
<Routes />
component - Using
useRoutes
- Using
createBrowserRouterV6
Available in @sentry/react
version 7.21.0
and above.
If you choose to create your router instance with createBrowserRouter
from the react-router-dom
package, you can use Sentry.wrapCreateBrowserRouterV6
to wrap it with the instrumentation:
import React from "react";
import {
createBrowserRouter,
createRoutesFromChildren,
matchRoutes,
useLocation,
useNavigationType,
} from "react-router-dom";
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.reactRouterV6BrowserTracingIntegration({
useEffect: React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes,
}),
],
tracesSampleRate: 1.0,
});
const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouterV6(
createBrowserRouter,
);
const router = sentryCreateBrowserRouter([
// your routes...
]);
Note
You can instrument createMemoryRouter
and createHashRouter
using the wrapCreateBrowserRouter
function.
If you're using the <Routes />
component to define your routes, wrap Routes
using Sentry.withSentryReactRouterV6Routing
. This creates a higher order component, which will enable Sentry to reach your router context. You can also use Sentry.withSentryReactRouterV6Routing
for Routes
inside BrowserRouter
. MemoryRouter
, and HashRouter
components:
import React from "react";
import ReactDOM from "react-dom";
import {
Routes,
Route,
BrowserRouter,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes,
} from "react-router-dom";
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.reactRouterV6BrowserTracingIntegration({
useEffect: React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes,
}),
],
tracesSampleRate: 1.0,
});
const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes);
ReactDOM.render(
<BrowserRouter>
<SentryRoutes>
<Route path="/" element={<div>Home</div>} />
</SentryRoutes>
</BrowserRouter>,
);
This is only needed at the top level of your app, rather than how v4/v5 required wrapping every <Route/>
you wanted parametrized.
Available in @sentry/react
version 7.12.1
and above.
If you specify your route definitions as an object to the useRoutes
hook, use Sentry.wrapUseRoutesV6
to create a patched useRoutes
hook that instruments your routes with Sentry.
wrapUseRoutesV6
should be called outside of a React component, as in the example below. It's also recommended that you assign the wrapped hook to a variable name starting with use
, as per the React documentation.
import React from "react";
import {
createRoutesFromChildren,
matchRoutes,
useLocation,
useNavigationType,
useRoutes,
} from "react-router-dom";
import { wrapUseRoutes } from "@sentry/react";
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
Sentry.reactRouterV6BrowserTracingIntegration({
useEffect: React.useEffect,
useLocation,
useNavigationType,
createRoutesFromChildren,
matchRoutes,
}),
],
tracesSampleRate: 1.0,
});
const useSentryRoutes = wrapUseRoutesV6(useRoutes);
function App() {
return useSentryRoutes([
// your routes...
]);
}
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root"),
);
Now, Sentry should generate pageload
/navigation
transactions with parameterized transaction names (for example, /teams/:teamid/user/:userid
), where applicable. This is only needed at the top level of your app, rather than how v4/v5 required wrapping every <Route/>
you wanted parametrized.
When using react-router
, errors thrown inside route elements will only be re-thrown in development mode while using strict mode
. In production, these errors won't be surfaced unless manually captured. If you don't have a custom error boundary in place, react-router
will create a default one that "swallows" all errors.
Note, that this only applies to render method and lifecycle errors since React doesn't need error boundaries to handle errors in event handlers.
To send errors to Sentry while using a custom error boundary, use the Sentry.captureException
method:
// router setup
const sentryCreateBrowserRouter = wrapCreateBrowserRouterV6(createBrowserRouter);
const router = sentryCreateBrowserRouter([
{
path: "/",
element: <YourLayout />,
children: [
{
path: "",
element: <Outlet />,
errorElement: <YourCustomRootErrorBoundary />,
children: [
// other routes ...
],
},
],
},
]);
// error boundary
import { useRouteError } from "react-router-dom";
import * as Sentry from "@sentry/react";
export function YourCustomRootErrorBoundary() {
const error = useRouteError() as Error;
React.useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<div>
<h1>Ouch!</h1>
</div>
);
}
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").