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

使用Tanstack Router时出现Cannot read properties of undefined错误求助

Tanstack Router v1.4.6 路由跳转报错:Cannot read properties of undefined (reading 'routeId')

错误信息

Cannot read properties of undefined (reading 'routeId')
TypeError: Cannot read properties of undefined (reading 'routeId')
    at http://localhost:3000/static/js/bundle.js:1449:89
    at J (http://localhost:3000/static/js/bundle.js:1450:9)
    at St (http://localhost:3000/static/js/bundle.js:1759:11)
    at http://localhost:3000/static/js/bundle.js:1878:15
    at renderWithHooks (http://localhost:3000/static/js/bundle.js:22462:22)
    at updateForwardRef (http://localhost:3000/static/js/bundle.js:25031:24)
    at beginWork (http://localhost:3000/static/js/bundle.js:27078:20)
    at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:12058:18)
    at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:12102:20)
    at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:12159:35)
ERROR
Invariant failed
    at g (http://localhost:3000/static/js/bundle.js:1101:19)
    at K (http://localhost:3000/static/js/bundle.js:1361:5)
    at renderWithHooks (http://localhost:3000/static/js/bundle.js:22462:22)
    at updateFunctionComponent (http://localhost:3000/static/js/bundle.js:25342:24)
    at beginWork (http://localhost:3000/static/js/bundle.js:27054:20)
    at HTMLUnknownElement.callCallback (http://localhost:3000/static/js/bundle.js:12058:18)
    at Object.invokeGuardedCallbackDev (http://localhost:3000/static/js/bundle.js:12102:20)
    at invokeGuardedCallback (http://localhost:3000/static/js/bundle.js:12159:35)
    at beginWork$1 (http://localhost:3000/static/js/bundle.js:32023:11)
    at performUnitOfWork (http://localhost:3000/static/js/bundle.js:31271:16)

代码实现

index.tsx(路由配置)

import React from "react";
import ReactDOM from "react-dom";
import { ApolloProvider } from "@apollo/client";
import client from "./client";
import App from "./App";
import {
  Outlet,
  RootRoute,
  Route,
  Router,
  RouterProvider,
} from "@tanstack/react-router";
import ExerciseTracker from "./ExerciseTracker";

const RootRouter = new RootRoute({
  component: () => (
    <>
      <Outlet />
    </>
  ),
});

const landingPageRoute = new Route({
  getParentRoute: () => RootRouter,
  path: "/",
  component: () => <App />,
});

const exerciseTrackerRoute = new Route({
  getParentRoute: () => RootRouter,
  path: "/exercise",
  component: () => <ExerciseTracker />,
});

const routeTree = RootRouter.addChildren([
  landingPageRoute,
  exerciseTrackerRoute,
]);

const router = new Router({ routeTree });

declare module "@tanstack/react-router" {
  interface Router {
    router: typeof router;
  }
}

ReactDOM.render(
  <ApolloProvider client={client}>
    <RouterProvider router={router} />
  </ApolloProvider>,
  document.getElementById("root")
);

App.tsx(首页组件)

import React from "react";
import { Link} from "@tanstack/react-router";

const App = () => {
  return (
    <>
      <h1>Welcome to Gym App</h1>
      <h2>Choose a page to navigate to:</h2>
      <button>
        <Link to="/exercise">Exercise tracker</Link>
      </button>
    </>
  );
};

export default App;

ExerciseTracker.tsx(目标页面组件)

import React, { useState } from "react";
import { GET_EXERCISES } from "./Queries/Queries";
import { CREATE_EXERCISE, DELETE_EXERCISE } from "./Mutations/Mutations";
import { useQuery, useMutation } from "@apollo/client";

function ExerciseTracker() {
  const [newExerciseName, setNewExerciseName] = useState("");
  const [newMuscleTrained, setNewMuscleTrained] = useState("");

  const { loading, error, data = [], refetch } = useQuery(GET_EXERCISES);

  const [createExercise] = useMutation(CREATE_EXERCISE);
  const [deleteExercise] = useMutation(DELETE_EXERCISE);

  const handleCreateExercise = async (e: any) => {
    e.preventDefault();
    try {
      const { data = [] } = await createExercise({
        variables: {
          name: newExerciseName,
          muscletrained: newMuscleTrained,
        },
      });

      console.log("Mutation response:", data);

      if (data && data.createExercise) {
        console.log("Created exercise:", data.createExercise);
        refetch();
        setNewExerciseName("");
        setNewMuscleTrained("");
      } else {
        console.error("Failed to create exercise. No data returned.");
      }
    } catch (error: any) {
      console.error("Error creating exercise:", error.message);
    }
  };

  const handleDeleteExercise = async (id: string) => {
    try {
      const { data } = await deleteExercise({
        variables: {
          id,
        },
      });

      console.log("Mutation response:", data);

      if (data && data.deleteExercise) {
        console.log("Deleted exercise with ID:", data.deleteExercise);
        refetch();
      } else {
        console.error("Failed to delete exercise. No data returned.");
      }
    } catch (error: any) {
      console.error("Error deleting exercise:", error.message);
    }
  };

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      <h1>Exercise Library</h1>

      <div>
        <h2>Create a New Exercise</h2>
        <label>
          Name:
          <input
            placeholder="Exercise Name"
            className="exerciseInput"
            aria-label="exerciseInput"
            type="text"
            value={newExerciseName}
            onChange={(e) => {
              setNewExerciseName(e.target.value);
            }}
          />
        </label>
        <label>
          Muscle Trained:
          <input
            placeholder="Muscle Trained"
            className="muscleInput"
            aria-label="muscleInput"
            type="text"
            value={newMuscleTrained}
            onChange={(e) => setNewMuscleTrained(e.target.value)}
          />
        </label>
        <button onClick={handleCreateExercise}>Create Exercise</button>
      </div>

      <h2>Exercises</h2>
      {data.exercises.map((exercise: any) => (
        <div key={exercise.id}>
          <h3>{exercise.name}</h3>
          <p>Muscle Trained: {exercise.muscletrained}</p>
          <button onClick={() => handleDeleteExercise(exercise.id)}>
            Delete Exercise
          </button>
        </div>
      ))}
    </div>
  );
}

export default ExerciseTracker;

问题分析与解决方案

核心问题

错误根源在于类型声明错误。在Tanstack Router v1中,扩展路由类型需要使用Register接口,而非Router接口。错误的类型声明会导致路由上下文无法正确传递,触发routeId未定义的报错。

修复步骤

  1. 修正类型声明:
    将index.tsx中的类型声明部分替换为:
declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}
  1. (可选)升级React渲染方式:
    如果使用React 18,建议将ReactDOM.render替换为createRoot,避免潜在的兼容性问题:
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root')!);
root.render(
  <ApolloProvider client={client}>
    <RouterProvider router={router} />
  </ApolloProvider>
);
  1. 验证Link组件使用:
    确保Link组件直接来自@tanstack/react-router,且没有被错误封装。当前App.tsx中的Link使用是正确的,无需修改。

验证修复

修改后重新启动项目,点击"Exercise tracker"链接即可正常跳转至目标页面,不会再出现routeId未定义的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 04:07:01