Search code examples
javascriptreactjsreact-routerreact-router-dom

code not working in latest react-router-dom in react router?


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

Solution

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