Search code examples
reactjstypescriptreact-router-dom

What is the cause of error about react-router-dom


index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

App.tsx

import { Reset } from "styled-reset";
import { NavBtn } from "./components/nav_btn";
import { Router } from "./router";

function App() {
  return (
    <>
      <Reset />
      <NavBtn />
      <Router />
    </>
  );
}

export default App;

nav_btn.tsx

import { Link } from 'react-router-dom';
import { styled } from 'styled-components';

const ProductManageBtn = styled.button`
  margin-right: 5px;
  border-radius: 10px;
`
const ChangeChargeBtn = styled.button`
  margin-right: 5px;
  border-radius: 10px;
`
const ProductPurchaseBtn = styled.button`
  margin-right: 5px;
  border-radius: 10px;
`

export function NavBtn() {
  return (
    <>
      <div>
        <ProductManageBtn>
          <Link to={`/product-manage`}>상품 관리</Link>
        </ProductManageBtn>
        <ChangeChargeBtn>
          <Link to={`/change-charge`}>잔돈 충전</Link>
        </ChangeChargeBtn>
        <ProductPurchaseBtn>
          <Link to={`/product-purchase`}>상품 구매</Link>
        </ProductPurchaseBtn>
      </div>
    </>
  )
}

router.tsx

import { BrowserRouter, Routes, Route } from "react-router-dom";
import { ProductManage } from "./pages/product_manage";
import { ChangeCharge } from "./pages/change_charge";
import { ProductPurchase } from "./pages/product_purchase";

export function Router() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path='/product-manage' element={<ProductManage />} />
        <Route path='/change-charge' element={<ChangeCharge />} /> 
        <Route path='/product-purchase' element={<ProductPurchase />} />
      </Routes>
    </BrowserRouter>
  )
}

The result I want is that when I click the Btn styled-component in nav_btn.tsx, the element component of router.tsx corresponding to the Link appears while the nav_btn component is maintained. But when I run this, the component doesn't show up, and I get this error:

Uncaught TypeError: Cannot destructure property 'basename' of 'react__WEBPACK_IMPORTED_MODULE_0__.useContext(...)' as it is null.
    at LinkWithRef (index.tsx:528:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at updateForwardRef (react-dom.development.js:19226:1)
    at beginWork (react-dom.development.js:21636:1)
    at HTMLUnknownElement. callCallback (react-dom.development.js:4164:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
    at invokeGuardedCallback (react-dom.development.js:4277:1)
    at beginWork$1 (react-dom.development.js:27451:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1), The above error occurred in the <Link> component:
    at LinkWithRef (http://localhost:3000/static/js/bundle.js:38573:7)
    at button
    at O (http://localhost:3000/static/js/bundle.js:45518:6)
    at div
    at NavBtn
    at App

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries., Uncaught TypeError: Cannot destructure property 'basename' of 'react__WEBPACK_IMPORTED_MODULE_0__.useContext(...)' as it is null.
    at LinkWithRef (index.tsx:528:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at updateForwardRef (react-dom.development.js:19226:1)
    at beginWork (react-dom.development.js:21636:1)
    at beginWork$1 (react-dom.development.js:27426:1)
    at performUnitOfWork (react-dom.development.js:26557:1)
    at workLoopSync (react-dom.development.js:26466:1)
    at renderRootSync (react-dom.development.js:26434:1)
    at recoverFromConcurrentError (react-dom.development.js:25850:1)
    at performConcurrentWorkOnRoot (react-dom.development.js:25750:1) \

Solution

  • You are rendering a react-router-dom (RRD) Link component outside the routing context provided by a RRD router component.

    Promote the BrowserRouter higher in the ReactTree such that it provides the routing context to as much of the app as it necessary. In this case it can simply be moved to the App component.

    App.tsx

    import { BrowserRouter } from "react-router-dom";
    import { Reset } from "styled-reset";
    import { NavBtn } from "./components/nav_btn";
    import { AppRoutes } from "./router";
    
    function App() {
      return (
        <BrowserRouter> // <-- provides routing context
          <Reset />
          <NavBtn />    // <-- consumes routing context
          <AppRoutes /> // <-- consumes routing context
        </BrowserRouter>
      );
    }
    
    export default App;
    

    router.tsx

    import { Routes, Route } from "react-router-dom";
    import { ProductManage } from "./pages/product_manage";
    import { ChangeCharge } from "./pages/change_charge";
    import { ProductPurchase } from "./pages/product_purchase";
    
    export function AppRoutes() {
      return (
        <Routes>
          <Route path='/product-manage' element={<ProductManage />} />
          <Route path='/change-charge' element={<ChangeCharge />} /> 
          <Route path='/product-purchase' element={<ProductPurchase />} />
        </Routes>
      );
    }