You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React页面路由配置报错:元素类型无效问题求助

React页面路由报错问题排查与修复

问题场景

在起始组件Home中配置路由,访问http://localhost:3000/时触发组件类型无效的错误。

起始组件Home(src/app/page.js)

"use client";
import { useState } from "react";
import { Nav, Navbar, Sidebar } from "./views/test.js";
import "./css/app.css";
import { BrowserRouter as Router, Route, Switch, Link } from "react-router-dom";
import { BlogPost } from "./views/blog.js";

export default function Home() {
      return (
        <Router>
          <div>
            <nav>
              <ul>
                <li>
                  <Link to="/">Home</Link>
                </li>
                <li>
                  <Link to="/blog">About</Link>
                </li>
              </ul>
            </nav>
            <Switch>
              <Route exact path="/">
                <Nav/>
              </Route>
              <Route path="/blog">
                <BlogPost/>
              </Route>
            </Switch>
          </div>
        </Router>
      );
    }

报错信息

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.

Check the render method of Home.

项目目录结构

├─node_modules
├─public
├─src
│  └─app
│     ├─api
│     ├─css
│     ├─router
│     ├─views
│     ├─Layout.js
│     └─page.js -> func Home()
├─README.md      
├─next.config.mjs  
├─package-lock.json  
├─postcss.config.mjs
├─jsconfig.json 
├─package.json
└─tailwind.config.js

涉及组件代码

BlogPost组件(src/app/views/blog.js)

import "../css/blog.css";
import { get_article_by_id } from "../api/server.js";
import remarkGfm from "remark-gfm";
import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { dark } from "react-syntax-highlighter/dist/esm/styles/prism";

function Article(props) {
  // console.log( "[debug] props.content is "+ typeof props.content);
  // console.log( "[debug] props.content : "+ props.content);
  return (
    <div>
      <ReactMarkdown className="md_title" children={props.title} />
      <ReactMarkdown
        className="md_content"
        children={props.content}
        remarkPlugins={[remarkGfm]}
        components={{
          code(props) {
            const { children, className, node, ...rest } = props;
            const match = /language-(\w+)/.exec(className || "");
            return match ? (
              <SyntaxHighlighter
                {...rest}
                PreTag="div"
                children={String(children).replace(/\n$/, "")}
                language={match[1]}
                style={dark}
              />
            ) : (
              <code {...rest} className={className}>
                {children}
              </code>
            );
          },
        }}
      />
    </div>
  );
}

export async function BlogPost() {
  // let { id } = useParams();
  let id = "101";
  const article = await get_article_by_id(id);
  console.log(article);
  return (
    <div className="md_main_vertical">
      <div className="md_main_horizontal">
        <Article title={article.title} content={article.content} />
      </div>
    </div>
  );
}

Nav组件(src/app/views/test.js)

'use client'
import React, { useState } from "react";
import { FaBars, FaTimes } from "react-icons/fa";
import "../css/test.css";

export function Navbar({ sidebarOpen, toggleSidebar }) {
  return (
    <header className="navbar">
      <button className="menu-button" onClick={toggleSidebar}>
        {sidebarOpen ? <FaTimes /> : <FaBars />}
      </button>
      <h1>Menghan Studio</h1>
    </header>
  );
}

export function Sidebar({ sidebarOpen }) {
  return (
      <div>
      <nav className={`sidebar ${sidebarOpen ? "open" : ""}`}>
        <ul>
          <li>
            <a href="#home">Home</a>
          </li>
          <li>
            <a href="#about">About</a>
          </li>
          <li>
            <a href="#services">Services</a>
          </li>
          <li>
            <a href="#contact">Contact</a>
          </li>
        </ul>
      </nav>
    </div>
  );
}

export function Nav() {
  const [sidebarOpen, setSidebarOpen] = useState(false);

  const toggleSidebar = () => {
    setSidebarOpen(!sidebarOpen);
  };
  return (
    <nav>
      <Navbar sidebarOpen={sidebarOpen} toggleSidebar={toggleSidebar} />
      <Sidebar sidebarOpen={sidebarOpen} />
    </nav>
  );
}

问题原因及修复方案

1. React Router版本不兼容

React Router v6已移除Switch组件,替换为Routes;同时Route组件需通过element属性传递组件,不再支持嵌套写法。

2. 异步组件使用错误

BlogPost是异步函数组件,直接作为路由组件会触发报错,需用Suspense包裹处理加载状态,或改为同步组件。

3. 修复后的Home组件代码

"use client";
import { useState, Suspense } from "react";
import { Nav, Navbar, Sidebar } from "./views/test.js";
import "./css/app.css";
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
// 懒加载异步组件并配合Suspense使用
const BlogPost = React.lazy(() => import("./views/blog.js").then(module => ({ default: module.BlogPost })));

export default function Home() {
      return (
        <Router>
          <div>
            <nav>
              <ul>
                <li>
                  <Link to="/">Home</Link>
                </li>
                <li>
                  <Link to="/blog">Blog</Link> {/* 统一文字与路径,避免混淆 */}
                </li>
              </ul>
            </nav>
            <Suspense fallback={<div>加载中...</div>}>
              <Routes>
                <Route path="/" element={<Nav/>} />
                <Route path="/blog" element={<BlogPost/>} />
              </Routes>
            </Suspense>
          </div>
        </Router>
      );
    }

额外优化:将BlogPost改为同步组件

如果不需要异步组件,可把数据获取逻辑移到useEffect中:

'use client'
import { useEffect, useState } from "react";
import "../css/blog.css";
import { get_article_by_id } from "../api/server.js";
import remarkGfm from "remark-gfm";
import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { dark } from "react-syntax-highlighter/dist/esm/styles/prism";

function Article(props) {
  return (
    <div>
      <ReactMarkdown className="md_title" children={props.title} />
      <ReactMarkdown
        className="md_content"
        children={props.content}
        remarkPlugins={[remarkGfm]}
        components={{
          code(props) {
            const { children, className, node, ...rest } = props;
            const match = /language-(\w+)/.exec(className || "");
            return match ? (
              <SyntaxHighlighter
                {...rest}
                PreTag="div"
                children={String(children).replace(/\n$/, "")}
                language={match[1]}
                style={dark}
              />
            ) : (
              <code {...rest} className={className}>
                {children}
              </code>
            );
          },
        }}
      />
    </div>
  );
}

export function BlogPost() {
  const [article, setArticle] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchArticle = async () => {
      let id = "101";
      const data = await get_article_by_id(id);
      setArticle(data);
      setLoading(false);
    };
    fetchArticle();
  }, []);

  if (loading) return <div>加载中...</div>;
  if (!article) return <div>文章未找到</div>;

  return (
    <div className="md_main_vertical">
      <div className="md_main_horizontal">
        <Article title={article.title} content={article.content} />
      </div>
    </div>
  );
}

内容的提问来源于stack exchange,提问作者StudioMenghan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 12:54:55