Here are some questions that people commonly have about React Router v6:
This question usually stems from the fact that you're using React class components, which don't support hooks. In React Router v6, we fully embraced hooks and use them to share all the router's internal state. But that doesn't mean you can't use the router. Assuming you can actually use hooks (you're on React 16.8+), you just need a wrapper.
import { useLocation, useNavigate, useParams } from "react-router-dom";
function withRouter(Component) {
function ComponentWithRouterProp(props) {
let location = useLocation();
let navigate = useNavigate();
let params = useParams();
return <Component {...props} router={{ location, navigate, params }} />;
}
return ComponentWithRouterProp;
}We mentioned this in the migration guide from v5 to v6, but it's worth repeating here.
In React Router v6 we switched from using v5's <Route component> and <Route render> APIs to <Route element>. Why is that?
For starters, we see React itself taking the lead here with the <Suspense fallback={<Spinner />}> API. The fallback prop takes a React element, not
a component. This lets you easily pass whatever props you want to your
<Spinner> from the component that renders it.
Using elements instead of components means we don't have to provide a
passProps-style API so you can get the props you need to your elements. For
example, in a component-based API there is no good way to pass props to the
<Profile> element that is rendered when <Route path=":userId" component={Profile} /> matches. Most React libraries who take this approach end
up with either an API like <Route component={Profile} passProps={{ animate: true }} /> or use a render prop or higher-order component.
Also, Route's rendering API in v5 was rather large. As we worked on v4/5, the
conversation went something like this:
// Ah, this is nice and simple!
<Route path=":userId" component={Profile} />
// But wait, how do I pass custom props to the <Profile> element??
// Hmm, maybe we can use a render prop in those situations?
<Route
path=":userId"
render={routeProps => (
<Profile routeProps={routeProps} animate={true} />
)}
/>
// Ok, now we have two ways to render something with a route. :/
// But wait, what if we want to render something when a route
// *doesn't* match the URL, like a Not Found page? Maybe we
// can use another render prop with slightly different semantics?
<Route
path=":userId"
children={({ match }) => (
match ? (
<Profile match={match} animate={true} />
) : (
<NotFound />
)
)}
/>
// What if I want to get access to the route match, or I need
// to redirect deeper in the tree?
function DeepComponent(routeStuff) {
// got routeStuff, phew!
}
export default withRouter(DeepComponent);
// Well hey, now at least we've covered all our use cases!
// ... *facepalm*At least part of the reason for this API sprawl was that React did not provide
any way for us to get the information from the <Route> to your route element,
so we had to invent clever ways to get both the route data and your own
custom props through to your elements: component, render props, passProps
higher-order-components ... until hooks came along!
Now, the conversation above goes like this:
// Ah, nice and simple API. And it's just like the <Suspense> API!
// Nothing more to learn here.
<Route path=":userId" element={<Profile />} />
// But wait, how do I pass custom props to the <Profile>
// element? Oh ya, it's just an element. Easy.
<Route path=":userId" element={<Profile animate={true} />} />
// Ok, but how do I access the router's data, like the URL params
// or the current location?
function Profile({ animate }) {
let params = useParams();
let location = useLocation();
}
// But what about components deep in the tree?
function DeepComponent() {
// oh right, same as anywhere else
let navigate = useNavigate();
}
// Aaaaaaaaand we're done here.Another important reason for using the element prop in v6 is that <Route children> is reserved for nesting routes. You can read more about this in the
guide about getting started with v6.
In v4 we would have just left the path prop off a route. In v5 we would have
wrapped our 404 element in a Route and used path="*". In v6 use the new
element prop, pass path="*" instead:
<Route path="*" element={<NoMatch />} />