skip to Main Content

in react I want to run an application-related react-router; that is fine; the problem is that specific code, such as "react-router-dom": "6.8.1," does not run in the latest react version and throws an error.

"Element type is invalid: expected a string (for built-in components)
or a class/function (for composite components) but got: undefined. You
likely forgot to export your component from the file it’s defined in,
or you might have mixed up default and named imports."

But if you change the version, it’s working fine, like in "react-router-dom": "5.2.1", This code is working fine, ,so my question is in "react-router-dom": :6.8.1 How to successfully run that code?in my App.js in code structure which thing should I have to change that code will run perfectly in 6.8.1 too?

import { useState } from "react";
import {
  BrowserRouter as Router,
  generatePath,
  Switch,
  Route,
  useHistory,
  useParams
} from "react-router-dom";



const products = [
  {
    id: "1",
    name: "Product 1"
  },
  {
    id: "2",
    name: "Product 2"
  },
  {
    id: "3",
    name: "Product 3"
  }
];

const Products = () => {
  const { id } = useParams();

  console.log(id);
  return (
    <div>
      <p>Lorem Ipsum</p>
      <p>Id: {id}</p>
    </div>
  );
};

const Home = () => {
  const [id, setId] = useState();
  const history = useHistory();
  console.log(history)
  const handleProceed = (e) => {
    id && history.push(generatePath("/products/:id", { id }));
  };

  return (
    <div
      style={{ display: "flex", flexDirection: "column", alignItems: "center" }}
    >
      <div>
        {products.map((product, i) => (
          <button
            key={i}
            onClick={(e) => {
              setId(product.id);
            }}
          >
            {product.name}
          </button>
        ))}
      </div>
      <button onClick={handleProceed} style={{ width: "250px" }}>
        Click
      </button>
    </div>
  );
};

export default function App() {
  return (
    <div className="App">
      <header>Heading</header>
      <Router>
        <Switch>
          <Route path="/products/:id">
            <Products />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </Router>
    </div>
  );
}

2

Answers


  1. For React Router v6, useNavigate should be used instead of useHistory (which no longer exists).

    const navigate = useNavigate();
    // ...
    id && navigate(generatePath("/products/:id", { id }));
    
    Login or Signup to reply.
  2. react-router@6 brought with it a ton of breaking changes. You should review the Upgrading from v5 migration guide for the full details.

    The Switch component was replaced by the Routes component which is required to directly wrap Routes you are rendering, and the useHistory hook was replaced by the useNavigate hook.

    import { useState } from "react";
    import {
      BrowserRouter as Router,
      generatePath,
      Routes,
      Route,
      useNavigate,
      useParams
    } from "react-router-dom";
    

    useNavigate returns a navigate function instead of a "history" object. Call navigate to issue imperative navigation actions.

    const Home = () => {
      const [id, setId] = useState();
      const navigate = useNavigate();
    
      const handleProceed = () => {
        navigate(generatePath("/products/:id", { id }));
      };
    
      return (
        <div
          style={{
            display: "flex",
            flexDirection: "column",
            alignItems: "center"
          }}
        >
          <div>
            {products.map((product) => (
              <button
                key={product.id}
                type="button"
                onClick={() => {
                  setId(product.id);
                }}
              >
                {product.name}
              </button>
            ))}
          </div>
          <button
            type="button"
            disabled={!id}
            onClick={handleProceed}
            style={{ width: "250px" }}
          >
            Click
          </button>
        </div>
      );
    };
    

    The Route component API/props changed, all the routed content is rendered on the Route component’s element prop.

    export default function App() {
      return (
        <div className="App">
          <header>Heading</header>
          <Router>
            <Routes>
              <Route path="/products/:id" element={<Products />} />
              <Route path="/" element={<Home />} />
            </Routes>
          </Router>
        </div>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search