MrDadox
MrDadox

Reputation: 1

Why my lazy loading isn't working in React?

I'm making a Single Page Application in React and i'm using the "lazy" function and the "Suspense" Component to import components only when is needed. But i have an strange error that i don't understand that says:

Error: Uncaught TypeError: can't convert item to string

My code in App.jsx:

import "./App.css";
import { lazy, Suspense } from "react";
import { Route } from "./Route.jsx";
import { Router } from "./Router.jsx";

const Home = lazy(() => import("./pages/Home.jsx"));
const About = lazy(() => import("./pages/About.jsx"));
const Search = lazy(() => import("./pages/Search.jsx"));

function App() {
  return (
    <main>
      <Suspense fallback={null}>
        <Router defaultComponent={() => <h1>404</h1>}>
          <Route path="/" Component={Home}></Route>
          <Route path="/about" Component={About}></Route>
          <Route path="/search/:query" Component={Search}></Route>
        </Router>
      </Suspense>
    </main>
  );
}

export default App;

I tried by asking ChatGPT and posting this problem in a discord server but they ignored me :(

Upvotes: 0

Views: 546

Answers (4)

I had the same issue, You can use "The imported page must be a default export. This means the home, about and search pages need to have export default function About."

Upvotes: 0

alberto WM
alberto WM

Reputation: 1

The imported page must be a default export. This means the home, about and search pages need to have export default function About.

I don't know the reason behind this, but lazy doesn't know which component to renderize without default

Upvotes: 0

MrDadox
MrDadox

Reputation: 1

While doing it that way does not give any more errors, it still does not take you to the pages in question. I guess it is due to the logic used by the whole program. What this does is to have a component called “Route” that has “path” and “Component” as parameters. The idea is that in the “Router”, it makes a .map of the “Route” children and returns in the variable “Page” the component to use, but as now the parameter “Component” is no longer used in “Route”, but the parameter “element”, it does not work. I have tried changing the “.Component” at the end of the declaration of the variable “Page” by “.element” but that doesn't work either. Do you have any idea why?

App.jsx:

import "./App.css";
import { lazy, Suspense } from "react";
import { Route } from "./Route.jsx";
import { Router } from "./Router.jsx";

const Home = lazy(() => import("./pages/Home.jsx"));
const About = lazy(() => import("./pages/About.jsx"));
const Search = lazy(() => import("./pages/Search.jsx"));

function App() {
  return (
    <main>
      <Suspense fallback={null}>
        <Router defaultComponent={() => <h1>404</h1>}>
          <Route path="/" element={<Home/>}></Route>
          <Route path="/about" element={<About/>}></Route>
          <Route path="/search/:query" element={<Search/>}></Route>
        </Router>
      </Suspense>
    </main>
  );
}

export default App;

Route.jsx:

// eslint-disable-next-line no-unused-vars
export function Route({ path, Component }) {
  return null;
}

Router.jsx:

import { EVENTS } from "./constants.js";
import { useState, useEffect, Children } from "react";
import { match } from "path-to-regexp";

export function Router({
  children,
  routes = [],
  defaultComponent: DefaultComponent = () => <h1>404</h1>,
}) {
  const [currentPath, setCurrentPath] = useState(window.location.pathname);

  useEffect(() => {
    const onLocationChange = () => {
      setCurrentPath(window.location.pathname);
    };

    window.addEventListener(EVENTS.PUSHSTATE, onLocationChange);
    window.addEventListener(EVENTS.POPSTATE, onLocationChange);

    return () => {
      window.removeEventListener(EVENTS.PUSHSTATE, onload);
      window.removeEventListener(EVENTS.POPSTATE, onLocationChange);
    };
  }, []);

  let routeParams = {};

  const routesFromChildren = Children.map(children, ({ props, type }) => {
    const { name } = type;
    const isRoute = name == "Route";

    return isRoute ? props : null;
  });

  let routesToUse = routes.concat(routesFromChildren);

  const Page = routesToUse.find(({ path }) => {
    if (path == currentPath) return true;

    const matcherUrl = match(path, { decode: decodeURIComponent });
    const matched = matcherUrl(currentPath);
    if (!matched) return false;

    routeParams = matched.params;
    return true;
  })?.Component;

  return Page ? (
    <Page routeParams={routeParams} />
  ) : (
    <DefaultComponent routeParams={routeParams} />
  );
}

Upvotes: 0

dev.muhammad
dev.muhammad

Reputation: 63

when you use lazy you have to use it like this, instead of Component attribute inside the Route you have to use element and the value of element should me like this <lazyVariableName/>

import "./App.css";
import { lazy, Suspense } from "react";
import { Route } from "./Route.jsx";
import { Router } from "./Router.jsx";

const Home = lazy(() => import("./pages/Home.jsx"));
const About = lazy(() => import("./pages/About.jsx"));
const Search = lazy(() => import("./pages/Search.jsx"));

function App() {
  return (
    <main>
      <Suspense fallback={null}>
        <Router defaultComponent={() => <h1>404</h1>}>
          <Route path="/" element={<Home/>}></Route>
          <Route path="/about" element={<About/>}></Route>
          <Route path="/search/:query" element={<Search/>}></Route>
        </Router>
      </Suspense>
    </main>
  );
}

export default App;

Upvotes: 0

Related Questions