Skip to content

解决“Uncaught TypeError: Cannot destructure property 'basename' of 'React2.useContext(...)' as it is null”错误

问题描述

在使用 React 和 react-router-dom 开发时,当你尝试在组件中使用 <Link> 标签时,可能会遇到以下错误提示:

Uncaught TypeError: Cannot destructure property 'basename' of 'React2.useContext(...)' as it is null.

这个错误通常发生在类似以下的导航栏组件代码中:

jsx
import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';

import { styles } from '../styles';
import { navLinks } from '../constansts';
import { logo, menu, close } from '../assets';

const Navbar = () => {
  const [active, setActive] = useState('');
  return (
    <nav className={`${styles.paddingX} w-full flex items-center py-5 fixed top-0 z-20 bg-primary`}>
      <div className="w-full flex justify-between items-center max-w-7x1 max-auto">
        <Link
          to="/"
          className="flex items-center gap-2"
          onClick={() => {
            setActive('');
            window.scrollTo(0, 0);
          }}
        >
          <img alt="logo" />
        </Link>
      </div>
    </nav>
  );
};

export default Navbar;

核心问题

此错误的根本原因是 <Link> 组件需要访问由 react-router-dom 提供的路由上下文,但当前应用没有正确配置路由提供器 BrowserRouter

解决方案

根本解决方法

在应用的顶层组件中包裹 BrowserRouter,确保所有路由组件都能访问必要的上下文:

步骤 1:在入口文件(index.js)中配置路由

jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  // 包裹应用提供路由上下文
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

步骤 2:正确组织App组件结构

确保导航栏等路由相关组件位于 BrowserRouter 内部但不是 Routes 的直接子元素:

jsx
import Navbar from './components/Navbar';
import HomePage from './pages/HomePage';
import { Routes, Route } from 'react-router-dom';

function App() {
  return (
    <div className="App">
      {/* 导航栏位于Routes外但在BrowserRouter内 */}
      <Navbar />
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/about" element={<AboutPage />} />
        <Route path="/*" element={<NotFoundPage />} />
      </Routes>
    </div>
  );
}

export default App;

常见错误

将导航组件作为<Routes>的直接子元素会导致渲染错误:

jsx
// ❌ 错误示例 - 不能放在Routes内
<Routes>
  <Navbar />
  <Route ... />
</Routes>

// ✅ 正确位置 - 与Routes并列
<>
  <Navbar />
  <Routes>...</Routes>
</>

替代解决方案

如果你需要在特定页面中使用不同的导航栏,可以使用Outlet

jsx
import { Outlet } from 'react-router-dom';

function Layout() {
  return (
    <div>
      <Navbar />
      {/* Outlet会渲染当前路由匹配的组件 */}
      <Outlet />
    </div>
  );
}

然后在路由配置中:

jsx
<Routes>
  <Route path="/" element={<Layout />}>
    <Route index element={<HomePage />} />
    <Route path="profile" element={<ProfilePage />} />
  </Route>
</Routes>

错误原理

当组件尝试使用 useContext 访问尚未建立的上下文时,会发生 "cannot destructure property... as it is null" 错误:

  1. BrowserRouter 为应用提供 RouterContext
  2. Link 组件通过 useContext(RouterContext) 访问路由信息
  3. BrowserRouter 缺失时,此上下文为 null
  4. 尝试从 null 中解构 basename 属性时抛出类型错误

最佳实践

  • 始终保持路由相关组件在 BrowserRouter 作用域内
  • 使用 React DevTools 检查组件树层级
  • 使用 npm ls react-router-dom 确保没有多版本冲突

常见问题排查

  1. 检查包裹位置:确保没有在 BrowserRouter 外部使用任何 react-router-dom 组件
  2. 验证依赖版本:使用 npm list react-router-dom 确保安装的是最新稳定版(6.x+)
  3. 路由配置问题:确保没有嵌套使用多个 BrowserRouter 组件
  4. 入口文件检查:确认路由配置在渲染根组件的文件(如 index.js)中

通过正确配置 BrowserRouter 并合理组织组件层级,即可彻底解决此类路由上下文错误。