49

After npm i --save react-router-dom and npm install --save with-router I tried to write

import {withRouter} from 'react-router';

But I Get this error Attempted import error: 'withRouter' is not exported from 'react-router'.



import React from 'react';
import PropTypes from 'prop-types';
import { Formik } from 'formik';
import {
  Box,
  Button,
  Card,
  CardContent,
  CardHeader,
  Divider,
 } from '@material-ui/core';
import { connect } from 'react-redux';
import jsonGR from "src/assets/data/greek.json";
import jsonEN from "src/assets/data/english.json";
import { LAN_EN }  from 'src/actions/types';
import CloudUploadIcon from '@material-ui/icons/CloudUpload';
import AddIcon from '@material-ui/icons/Add';
import axios from 'axios';
import LinearProgress from '@material-ui/core/LinearProgress';
import Typography from '@material-ui/core/Typography';
import { withRouter } from 'react-router'

class ProfileDetails extends React.Component {
//code
}
};
  ProfileDetails.propTypes = {
    className: PropTypes.string
  };

const mapStateToProps = state => {
  return { loginsession: state.loginsession,
    selectedlan: state.selectedlan };
};

export default withRouter(ProfileDetails);

File package.json with dependencies that I make npm install in the project and all the necessary information. I can't understand where is the problem I try with many ways but no one worked

{
  "name": "react-material-dashboard",
  "author": "Apanay22",
  "licence": "MIT",
  "version": "1.0.0",
  "private": false,
  "scripts": {
    "start": "react-scripts start http-server ",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "dependencies": {
    "@material-ui/core": "^4.11.0",
    "@material-ui/icons": "^4.9.1",
    "@material-ui/lab": "^4.0.0-alpha.56",
    "@material-ui/styles": "^4.10.0",
    "axios": "^0.21.1",
    "bcrypt": "^5.0.0",
    "chart.js": "^2.9.3",
    "clsx": "^1.1.1",
    "compress.js": "^1.1.2",
    "cors": "^2.8.5",
    "csv-parse": "^4.15.1",
    "express": "^4.17.1",
    "formik": "^2.1.5",
    "glob": "^7.1.6",
    "gulp": "^4.0.2",
    "history": "^5.0.0",
    "lodash": "^4.17.19",
    "material-ui-popup-state": "^1.7.1",
    "moment": "^2.27.0",
    "mui-datatables": "^3.7.6",
    "nprogress": "^0.2.0",
    "papaparse": "^5.3.0",
    "prop-types": "^15.7.2",
    "react": "^16.13.1",
    "react-chartjs-2": "^2.10.0",
    "react-csv-reader": "^3.2.1",
    "react-dom": "^16.13.1",
    "react-feather": "^2.0.8",
    "react-helmet": "^6.1.0",
    "react-hot-toast": "^1.0.2",
    "react-image-file-resizer": "^0.4.2",
    "react-navigation": "^4.4.4",
    "react-perfect-scrollbar": "^1.5.8",
    "react-redux": "^7.2.2",
    "react-router": "^6.0.0-beta.0",
    "react-router-dom": "^6.0.0-beta.0",
    "react-scripts": "^3.4.1",
    "react-toast-notifications": "^2.4.0",
    "react-toastify": "^7.0.2",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0",
    "use-history": "^1.4.1",
    "uuid": "^8.3.0",
    "with-router": "^1.0.1",
    "yup": "^0.29.3"
  },
  "devDependencies": {
    "@types/react-router-dom": "^5.1.7",
    "concurrently": "^5.3.0",
    "eslint": "^6.8.0",
    "eslint-config-airbnb": "^18.2.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-import": "^2.22.0",
    "eslint-plugin-jsx-a11y": "^6.3.1",
    "eslint-plugin-prettier": "^3.1.4",
    "eslint-plugin-react": "^7.20.3",
    "eslint-plugin-react-hooks": "^2.5.1",
    "prettier": "^1.19.1"
  },
  "proxy": "http://localhost:9000"
}
apanay22
  • 567
  • 1
  • 5
  • 10
  • FYI: Here is the question regarding `Switch` being not exported: https://stackoverflow.com/q/63124161/630364 – yaobin May 19 '22 at 14:46

13 Answers13

19

I had the same issue. I fixed it by downgrading react-router and react-router-dom to version 5.2.0.

Just run npm install react-router-dom@5.2.0 and npm install react-router@5.2.0. This should fix the issue with withRouter().

codesnerd
  • 767
  • 2
  • 8
  • 23
seba.lukic
  • 313
  • 2
  • 4
16

//you can import this and this function

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;
  }
Jack Li
  • 161
  • 1
  • 2
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 04 '21 at 07:22
10

From the FAQ page, you do need to have React 16.8+ to be able to use hooks. I'm on 17.0.2, seems to work fine:

https://reactrouter.com/en/main/start/faq

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;
}
Dave Petersen
  • 109
  • 1
  • 4
7

Well Since withRouter is removed from react-router v6 you can create your own function.

import { useNavigate } from 'react-router';

export const withRouter = (Component) =>{
    const Wrapper = (props) =>{
        const history = useNavigate();
        return <Component history={history} {...props}/>
    } 
    return Wrapper;
}
  • How to i use the above function in my component – ekibet Mar 13 '23 at 18:15
  • use withRouter function as a HOC Higher Order Component below is the link of complete documentation of HOC function https://reactjs.org/docs/higher-order-components.html#:~:text=A%20higher%2Dorder%20component%20(HOC,and%20returns%20a%20new%20component. – Shoaib Muhammad Arif Mar 14 '23 at 08:22
6

I saw you are using react-router-dom 6 and it is a quite different from the version 5. You have 2 options, downgrade to the version 5 or try implement the new version here is the new documentation documentation

4

For those who prefer class components to function components the equivalent solution for react-route-dom v6 is:

import { useLocation } from "react-router-dom";

const withLocation = Component => props => {
    const location = useLocation();
  
    return <Component {...props} location={location} />;
  };


export default withLocation( MyComponent)

Same applies to useNavigation and useParams.

I didn't find ready made wrappers in the library at the time being.

MiguelSlv
  • 14,067
  • 15
  • 102
  • 169
0

Try to install the old version e.g version 5. It won't work on the latest version 6. And i can see that's what you're using.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 25 '21 at 18:23
0

In my case React app stop re-rendering when the route changes after migration to React v.18;

For now I've left react-router-dom on v.5 but to solve the issue moved React Strict mode inside the Route:

          <HashRouter>
            <React.StrictMode>
                <App />
            </React.StrictMode>
          </HashRouter>` 
Dima Dorogonov
  • 2,297
  • 1
  • 20
  • 23
0

Using react-router 6, withRouter was removed.

You can follow the guide from the official website.

Create your own file "withRouter.js"

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;
}
jeremylb
  • 29
  • 3
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/33401664) – TAbdiukov Dec 17 '22 at 03:23
0

If you need to use params for data fetching, writing a logic in your ClassComponent and render component depending on them, then create wrapper for your ClassComponentContainer

import { useLocation, useParams } from 'react-router-dom';
import ClassComponentContainer from './ClassComponentContainer';

export default function ClassComponentWrap(props) {
 const location = useLocation();
 const params = useParams();

 return <ClassComponentContainer location={location} params={params} />
}

after it just use params in ClassComponent which is in props

import React from 'react';
import { connect } from 'react-redux';
import axios from 'axios';
import PresentationComponent from './PresentationComponent';

class ClassComponent extends React.Component {
 componentDidMount() {
  let postID = this.props.params.postID;
  axios.get(`https://jsonplaceholder.typicode.com/posts/${postID}`)
       .then((response) => {console.log(response)})
 }
 render() {
  return <PresentationComponent {...this.props} />
 }
}

const mapStateToProps = (state) => {...}
const mapDispatchToProps = (dispatch) => {...}

const ClassComponentContainer = connect(mapStateToProps, mapDispatchToProps)(ClassComponent);

export default ClassComponentContainer;

and use ClassComponentWrap component in Route element attribute

import { BrowserRouter, Route, Routes } from "react-router-dom";
import ClassComponentWrap from './components/ClassComponentWrap';

export default function App(props) {
 return (
  <BrowserRouter>
   <Routes>
    <Route path="/posts/:postID?" element={<ClassComponentWrap />} />
   </Routes>
  </BrowserRouter>
 );
}
0

Apart from this question

if you want to get params passed by the HTTP router

instead of using (withRouter and match.params.id) use useParams() to get the http parameters

import {useParams} from "react-router-dom";

const Student = (props) => {
    
        return (

            <>
                <h1>Student Component: {useParams().id}</h1>
            </>

        )           
}
export default Student;
sumit
  • 1
-1

you can try to use useSelector from react-redux if you wanna access the state

const  isAuthenticated = useSelector((state) => isAuthenticated(state));
-15
import {withRouter} from 'react-router-dom';
Slava Rozhnev
  • 9,510
  • 6
  • 23
  • 39
  • 3
    Welcome to Stack Overflow! While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Yunnosch Jun 12 '21 at 14:52
  • 3
    Especially please explain the difference to the answer by Dakota. I do not see any and get the impression that you are proposing the same. That makes me wonder whether you are aware of that older answer. – Yunnosch Jun 12 '21 at 14:53
  • 1
    Ahah, "Welcome to our friendly SO": -6 points right from the start :D – chill appreciator Nov 26 '21 at 09:55