blog logo
iaman

Dynamic Component & Lazy


Why it's needed

1. Easier maintenance as the number of pages grows

2. Fewer unnecessary js calls & better initial render performance

Groundwork

1. Map the menu paths in the DB to those on the front end

2. Reach the page paths using node.js's `glob` object

( this is what makes the pages reachable after deployment )

The approach

#Creating the dynamic component

import { lazy, Suspense } from "react";
import { Spin } from "antd";
const componentPages: any = import.meta.glob("../pages/**/**/**.tsx");

const DynamicPathComponent = (props: any) => {
    const LazyComponent = lazy(
        typeof componentPages[props.componentPath] === "function" ? componentPages[props.componentPath] : () => {}
    );
    return (
        <Suspense fallback={<Spin tip="Loading" size="large"></Spin>}>
            <LazyComponent />
        </Suspense>
    );
};

export default DynamicPathComponent;

#Applying every page to the Router

const FncChildrenPathAndElement = (totalMenu) => {
        const childrenMenuArr: ChildrenProps[] = totalMenu
            .map((list) => (list.children !== null ? list.children : []))
            .map((arr) => arr.map((obj) => (obj.menuUrl !== null ? obj.menuUrl : [])))
            .filter((val, idx) => val.length > 0)
            .join()
            .split(",")
            .map((path) => {
                return {
                    path: path.split("..")[1].split(".tsx")[0], 
                    element: <DynamicPathComponent componentPath={path} />,
                    errorElement: <ElementComponentError />
                };
            });
        return childrenMenuArr;
    };

  const dynamicMenuPages = [
            {
                path: "/login", 
                element: <LoginLayout />,
                children: [{ index: true, element: <Login />, errorElement: <ElementComponentError /> }],
                errorElement: <Error />
            },
            {
                path: "/",
                element: <MainLayout _Menu={totalMenuList} />,
                children: defaltMainMenu.concat(...childrenMenuList),
                errorElement: <Error />
            },
        ];

        setDynamicPage(createBrowserRouter([...dynamicMenuPages]));

(rest of the source omitted)
...

 return <>{isLoading && <RouterProvider router={dynamicPage} />}</>;