Reactreact-router-dom

Multiple layout sử dụng react router trong reactjs

By Thái Nguyễn
Picture of the author
Published on
image alt attribute

Sau bài viết: Cách sử dụng React Router giới thiệu các thuật ngữ cơ bản nhất về React Router, bài viết này mình muốn giới thiệu 1 chức năng phổ biến đó là Multiple Layout trong react sử dụng thư viện React Router.

Multiple Layout là gì?

Layout đại diện cho kết cấu tạo thành của một Web Page. Hãy cùng xem ví dụ về 1 layout bao gồm header, sidebar, footer, content:

genesis-full-height-sidebar-header-footer-with-content

Trong một Application sẽ có 1 hoặc nhiều layout khác nhau, layout của Page Login sẽ khác với Layout của Page sau khi đã Login, Layout module Product sẽ khác với Layout module User Management. Điểm khác nhau ở đây có thể là có các thành phần của layout hoặc style.

Tạo Multiple Layout sử dụng React Router

Trong demo này mình sẽ tạo 2 Layout là Application Layout sử dụng cho các Page đã đăng nhập, Empty Layout để cho các Page không cần Layout như Page Login.

Mình sẽ tạo Home page sử dụng Application LayoutLogin page sử dụng Empty Layout. Để xem tổng quan các Page dùng trong demo, hãy cùng xem khai báo routes trong file App.tsx:

// App.tsx
import React from "react";

import "./App.css";
import { Navigate, useRoutes } from "react-router-dom";
const HomePage = React.lazy(() => import("./pages/Home"));
const LoginPage = React.lazy(() => import("./pages/Login"));
const EmptyLayout = React.lazy(() => import("./layouts/EmptyLayout"));
const ApplicationLayout = React.lazy(
  () => import("./layouts/ApplicationLayout")
);

function App() {
  const routes = useRoutes([
    {
      path: "/",
      index: true,
      element: <Navigate to="/home" />,
    },
    {
      path: "/",
      element: <ApplicationLayout />,
      children: [
        {
          path: "home",
          element: <HomePage />,
        },
      ],
    },
    {
      path: "/",
      element: <EmptyLayout />,
      children: [
        {
          path: "login",
          element: <LoginPage />,
        },
      ],
    },
  ]);
  return routes;
}

export default App;

Theo cách define ở trên, các layouts ApplicationLayoutEmptyLayout sẽ có 1 hoặc nhiều children khác nhau. Việc render các children sẽ phụ thuộc logic nằm trong Layout. Chi tiết hơn chúng ta cùng xem layout component EmptyLayoutApplicationLayout:

// ApplicationLayout.tsx
import React from "react";
import { Outlet } from "react-router-dom";
import Header from "../components/Header";
import Footer from "../components/Footer";

const ApplicationLayout = () => {
  return (
    <div className="h-screen flex flex-col bg-blue-50">
      <Header />
      <div className="m-16 flex-1 bg-rose-100">
        <Outlet />
      </div>
      <Footer />
    </div>
  );
};

export default ApplicationLayout;

// EmptyLayout.tsx
import React from "react";
import { Outlet } from "react-router-dom";

const EmptyLayout = () => {
  return (
    <div className="min-h-screen flex items-center justify-center bg-green-100">
      <Outlet />
    </div>
  );
};

export default EmptyLayout;

<Outlet /> component được import từ react-router-dom chính là component sẽ render nội dung của các elements trong thuộc tính children ở trên.

Ở trong ví dụ, <Outlet /> sẽ hiển thị HomePage hoặc LoginPage tuỳ thuộc vào route match với đường dẫn nào.

Cùng xem qua demo

/login page:

Screenshot 2023-11-06 at 17.15.41

/home page:

Screenshot 2023-11-06 at 17.16.06

Với việc tạo layout như trên, nếu chúng ta tạo ra các page mới có chung layout sẽ rất nhanh chóng và thuận tiện.

VD tạo thêm 1 page Products để hiển thị thông tin sản phẩm, page này cũng có Header và Footer giống Home page trong ví dụ trên. Chúng ta chỉ cần khai báo như sau:

// App.tsx
...
const ProductsPage = React.lazy(() => import("./pages/Products"));

function App() {
  const routes = useRoutes([
    ...
    {
      path: "/",
      element: <ApplicationLayout />,
      children: [
        {
          path: "home",
          element: <HomePage />,
        },
        {
          path: "products",
          element: <ProductsPage />,
        },
      ],
    },
    ...
  ]);
  return routes;
}

export default App;

Như vậy chúng ta chỉ cần quan tâm đến nội dung của Products page. Các thành phần khác của Layout như Header, Footer sẽ được tái sử dụng. Một điều tuyệt với khác đó là khi navigation giữa các page có chung layout, thì chỉ children bị render còn các thành phần dùng chung trong layout sẽ không bị rerender. Sẽ tốt hơn cho performance.


Conclusion

Chúng ta đã hoàn thành xong cách sử dụng Multiple Layout sử dụng React Router trong Reactjs. Đây là một chức năng giúp các Routes được định nghĩa rõ ràng hơn, tăng khả năng tái sử dụng các component, tránh rerender không cần thiết.

Trong bài tiếp theo chúng ta sẽ cùng tìm hiểu cách xác thực và phân quyền cho Application sử dụng Protected Route và customize RouteObject trong React Router:

https://www.nguyenvanthai.com/blog/react/protected-routes-trong-react-js-su-dung-react-router-dom-v6

Hãy comment nếu bạn có điều gì thắc mắc hoặc muốn trao đổi thêm về bài viết này nhé 🥰