Yusuf
Yusuf

Reputation: 3443

'withRouter' is not exported from 'react-router-dom'

Failed to compile. Attempted import error: 'withRouter' is not exported from 'react-router-dom'.

My code like, also I have installed react-router-dom an react-route and I have respin the app 10 time now

import React from 'react';
import {withRouter} from 'react-router-dom';

import './menu-item.scss';

const MenuItem = ({ title, imageUrl, size, history }) => (
  <div className={`${size} menu-item`}>
    <div
      className='background-image'
      style={{
        backgroundImage: `url(${imageUrl})`,
      }}
    />
    <div className='content'>
      <h1 className='title'>{title.toUpperCase()}</h1>
      <span className='subtitle'>SHOP NOW</span>
    </div>
  </div>
);

export default withRouter(MenuItem);

Upvotes: 8

Views: 25870

Answers (5)

Drew Reese
Drew Reese

Reputation: 202618

If you accidentally installed react-router-dom v6 then the withRouter HOC no longer exists. Either revert back to v5 (run npm install -s react-router-dom@5), or roll your own custom withRouter HOC to inject the props you need or convert the components to function components and use the React hooks.

Create custom withRouter Higher Order Component

From the FAQ: What happened to withRouter I need it

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;
}

Convert to function component

There is now also no longer a history object to use, it was replaced by a navigate function accessed via the useNavigate hook. It's not clear where history was being used previously, but if you need to imperatively navigate the following is how you access the navigation. If staying with v6 then the following is how to access the navigate function.

import React from 'react';
import { useNavigate } from 'react-router-dom';

import './menu-item.scss';

const MenuItem = ({ title, imageUrl, size }) => {
  const navigate = useNavigate();

  // navigate("/targetPath")

  return (
    <div className={`${size} menu-item`}>
      <div
        className='background-image'
        style={{
          backgroundImage: `url(${imageUrl})`,
        }}
      />
      <div className='content'>
        <h1 className='title'>{title.toUpperCase()}</h1>
        <span className='subtitle'>SHOP NOW</span>
      </div>
    </div>
  )
};

export default MenuItem;

Upvotes: 14

mystes
mystes

Reputation: 11

in menu-item.component.jsx you can use the useNavigate just like this one

import React from "react";
import { useNavigate } from "react-router-dom";

import "./menu-item.styles.scss";

const MenuItem = ({ title, imageUrl, size, history, linkUrl, match }) => {
  let navigate = useNavigate();
  return (
    <div className={`${size} menu-item`} onClick={() => navigate(`${linkUrl}`)}>
      <div
        className="background-image"
        style={{
          backgroundImage: `url(${imageUrl})`,
        }}
      ></div>

      <div className="content">
        <h1 className="title">{title.toUpperCase()}</h1>
        <span className="subtitle">SHOP NOW</span>
      </div>
    </div>
  );
};

export default MenuItem;

Also, in App.js you should import Routes and Route from react-router-dom and make your code like this:

import React from "react";
import { Routes, Route } from "react-router-dom";

import "./App.css";
import HomePage from "./pages/homepage/homepage.component";

const HatsPage = () => (
  <div>
    <h1>Hats page</h1>
  </div>
);

function App() {
  return (
    <div>
      <Routes>
        <Route exact path="/" element={<HomePage />} />
        <Route path="/hats" element={<HatsPage />} />
      </Routes>
    </div>
  );
}

export default App;

As for me, this works.

Upvotes: 1

Yusuf
Yusuf

Reputation: 3443

thanks to Drew Reese -great shout-, and similar to Switch ( will throw the same error ) here is the downgrade command, just make sure you are in the right directory

npm install [email protected]

Upvotes: 2

Ditter Raquion
Ditter Raquion

Reputation: 41

You can use useLocation hook and destructure 'pathname' property from it to make the navigated link in the onClick() function dynamic.

Here's a sample of the code that worked for me:

  import React from "react";
  import { useLocation, useNavigate } from "react-router-dom";
  import "./menu-item.styles.scss";

  const MenuItem = ({ title, imageUrl, size, linkUrl, match }) => {
    let navigate = useNavigate();
    // destructured "pathname" property from useLocation()
    let { pathname } = useLocation();
    // consoloe.log(pathname)
    return (
      <div className={`${size} menu-item`} onClick={() => navigate(`${pathname}${linkUrl}`)}>
        <div
          className="background-image"
          style={{
            backgroundImage: `url(${imageUrl})`,
          }}
        />
        <div className="content">
          <h1 className="title">{title.toUpperCase()}</h1>
          <span className="subtitle">SHOP NOW</span>
        </div>
      </div>
    );
  };

  export default MenuItem;

Upvotes: 2

shrey tandel
shrey tandel

Reputation: 1

try this it worked for me

import React from "react";
import { useNavigate } from "react-router-dom";

import "./menu-item.styles.scss";

const MenuItem = ({ title, imageUrl, size, history, linkUrl, match }) => {
  const navigate = useNavigate();

  return (
    <div className={`${size} menu-item`} onClick={() => navigate(`hats`)}>
      <div
        className="background-image"
        style={{
          backgroundImage: `url(${imageUrl})`,
        }}
      ></div>

      <div className="content">
        <h1 className="title">{title.toUpperCase()}</h1>
        <span className="subtitle">SHOP NOW</span>
      </div>
    </div>
  );
};

export default MenuItem;

Upvotes: 0

Related Questions