We are having legacy class based code for which we are trying to migrate to latest react router that is version 6. During migration we are getting this error:
Module '"react-router-dom"' has no exported member 'RouteComponentProps'
We have added withRouter
wrapper to add the legacy support.
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;
}
export default withRouter;
Our class based component looks like this:
import { Route, RouteComponentProps, Routes } from "react-router-dom";
class App extends React.Component<{} & RouteComponentProps<{}>, IState> {
constructor(props: RouteComponentProps<{}>) {
super(props);
this.state = {
prop1: null
};
}
componentDidMount() {
if (this.props.location.pathname === "/test") {
window.location.reload();
}
};
render() {
return (
<Routes>
<Route path="/test" element={<Test />} />
</Routes>
)
}
}
export default withRouter(App);
How do I fix this issue?
react-router-dom@6
doesn't export any RouteComponentProps
type. In fact, RRD6 completely did away with route props, the former location
, navigate
, and params
values are now accessed using useLocation
, useNavigate
, and useParams
respectively.withRouter
Higher Order Component isn't injecting "route params", it is injecting a single prop named router
that has the "route params".In most cases the answer to "How do I fix this issue?" is to convert the Class components to Function components and use the hooks directly. For the sake of addressing your issue with legacy code though you'll have to type the "route props" manually yourself.
Example:
import {
Location,
NavigateFunction,
Params,
useLocation,
useNavigate,
useParams,
} from "react-router-dom";
export interface RouterProps {
location: Location;
navigate: NavigateFunction;
params: Params;
}
export interface WithRouter {
router: RouterProps;
}
function withRouter(Component: any) {
function ComponentWithRouterProp(props: any) {
const location = useLocation();
const navigate = useNavigate();
const params = useParams();
return <Component {...props} router={{ location, navigate, params }} />;
}
return ComponentWithRouterProp;
}
export default withRouter;
interface IState {
prop1: .....
}
interface IProps extends WithRouter {
.....
}
class App extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
prop1: null
};
}
componentDidMount() {
if (this.props.router.location.pathname === "/test") {
// ...
}
}
render() {
return (
<Routes>
<Route path="/test" element={<Test />} />
</Routes>
);
}
}
export default withRouter(App);
Note: React Class components have been effectively deprecated since February 2019 when React hooks were released. It's now 2024, you should really try to write modern React using Function components. This is especially true when working with newer versions of libraries like react-router-dom
that exclusively use React hooks.