I keep encountering this error when trying to create multiple pages in app.js - what to do?

28 views Asked by At

I am trying to make a portfolio website (using React codesandbox) with multiple pages that talk about me, and I encountered an error message stating "Element type is invalid" in my React application. This error typically occurs when trying to render a component that is either not defined or not exported properly.

In my code snippet, the error occurs in the App component when rendering routes using React Router. I don't know how I can successfully debug this error. Can someone help me understand what had happened and what can I do to correct this error? Thank you for taking your time on this.

Screenshot of error message in codesandbox

App.js

// App.jsx
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Landing from "./pages/landing";
import List from "./pages/toc";
import About from "./pages/about";
import "./styles.css";

const App = () => {
  return (
    <Router>
      <div className="app">
        <Switch>
          <Route exact path="/" component={Landing} />
          <Route path="/table-of-contents" component={List} />
          <Route path="/about" component={About} />
        </Switch>
      </div>
    </Router>
  );
};

export default App;

I have tried to debug which Route is messing up the code but it comes up that the Route itself is flawed. I don't know the exact steps to accomplish the react-router-dom page creation.

P.S.: Here is the link to a forked codesandbox page:

1

There are 1 answers

1
Drew Reese On BEST ANSWER

Odd, normally you should have seen an error stating something to the effect of "Switch not exported from react-router-dom, these are the named exports ....". Your code is the older React-Router-DOM v4/5 syntax but you have specified React-Router-DOM v6 as a dependency.

Using React-Router-DOM v4/5

If you want to continue using your current code then you'll need to downgrade the react-router-dom dependency.

  • Uninstall the current v6 version: npm uninstall --save react-router-dom
  • Install latest v5: npm install --save react-router-dom@5

Using React-Router-DOM v6

If you want to use the current version of react-router-dom then you'll need to fix several breaking changes.

  • There is no longer any Switch component, it was replaced by the Routes component.
  • The Route component API was changed a bit as well, there is no longer any component (and render and children function prop), replaced by a single element prop taking a React.ReactNode, a.k.a. JSX, value.
  • The useHistory hook was removed, replaced by a useNavigate hook that returns a navigate function instead of the history object.

Update App to import and use the Routes component. Render the routed content correctly on the element prop.

import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Landing from "./pages/landing";
import List from "./pages/toc";
import About from "./pages/about";
import "./styles.css";

const App = () => {
  return (
    <Router>
      <div className="app">
        <Routes>
          <Route path="/" element={<Landing />} />
          <Route path="/table-of-contents" element={<List />} />
          <Route path="/about" element={<About />} />
        </Routes>
      </div>
    </Router>
  );
};

export default App;

Replace the useHistory hook with the useNavigate hook in the routed components.

Landing

import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import "/src/styles/hero.css";

const Landing = () => {
  const [typingComplete, setTypingComplete] = useState(false);
  const navigate = useNavigate();

  const handleClick = () => {
    // Navigate to the '/table-of-contents' route when clicked
    navigate("/table-of-contents");
  };

  const handleTypingComplete = () => {
    setTypingComplete(true);
  };

  return (
    <div className="landing" onClick={handleClick}>
      <h1
        className="title typing-animation glow-text"
        onAnimationEnd={handleTypingComplete}
      >
        John Doe
      </h1>
      <h2 className={`subtitle ${typingComplete ? "fade-in glow-text" : ""}`}>
        <span>
          <em>Click</em> to get started
        </span>
      </h2>
    </div>
  );
};

export default Landing;

Toc

import React from "react";
import { useNavigate } from "react-router-dom";
import logo from "../pictures/trace.svg";
import "../styles/hero.css";
import "../styles/toc.css";
import Card from "../components/card";

const List = () => {
  const navigate = useNavigate();

  // Function to handle card click and navigate to a specific route
  const handleCardClick = (route) => {
    navigate(route); // Navigate to the specified route
  };

  return (
    <div className="toc">
      <h1 className="h1 toc-heading">Table Of Contents</h1>
      <div className="cards-container">
        {/* Add onClick handlers to the cards */}
        <Card
          title="1"
          className="item"
          content="About Me"
          onClick={() => handleCardClick("/about-me")} // Navigate to "/about-me" route
        />
        <Card
          title="2"
          className="item"
          content="Resume"
          onClick={() => handleCardClick("/resume")} // Navigate to "/resume" route
        />
        <Card
          title="3"
          className="item"
          content="Projects"
          onClick={() => handleCardClick("/projects")} // Navigate to "/projects" route
        />
        <Card
          title="4"
          className="item"
          content="Contact"
          onClick={() => handleCardClick("/contact")} // Navigate to "/contact" route
        />
      </div>
      <div className="logo-container">
        <img alt="" src={logo} width="90" height="60" className="logo" />
      </div>
    </div>
  );
};

export default List;

You may want to read through the Upgrading from v5 migration guide for complete details for all the breaking changes in v6, and review the Main Concepts for a high-level overview of the new features.