MinJeung-Kim / NextJS-v13--Study

Next.js(v13)의 모든것😎
https://next-js-v13-study.vercel.app
0 stars 0 forks source link

UI 성능 개선 #21

Open MinJeung-Kim opened 1 year ago

MinJeung-Kim commented 1 year ago

Loading UI

전체 페이지 로딩UI

export default function ProductsLoading() {

return

로딩중 입니다...⏳

; }


![image](https://github.com/MinJeung-Kim/NextJS-v13--Study/assets/79193369/4ff855cf-d174-4836-8022-2f63003a3a80)

### 동작 원리
- `<Layout>`에서 페이지가 보여지는 부분을 Suspense로 감싸줌.
- `<Page />`컴포넌트가 준비되기 전에 `fallback`으로 명시한 `<Loading />` 를 보여준 후 준비된 `<Page />`컴포넌트를 보여줌.
![image](https://github.com/MinJeung-Kim/NextJS-v13--Study/assets/79193369/664539f0-7f82-4888-93ff-8287380f24ae)

### 성능 개선 ( 작은 단위 로딩 UI )
- 페이지 단위로 로딩 컴포넌트를 사용할 수 있지만, 필요에 따라서 Suspense Boundaries를 사용할 수 있음.
- 데이터 병렬 요청시 의미있는 UI를 보여주기 위한 코드.

<Suspense fallback={

Loading...
}>

   ```ts
   import { getArtist, getArtistAlbums, type Album } from './api';

   export default async function Page({
     params: { username },
   }: {
     params: { username: string };
   }) {
     // 데이터 요청을 기다리지 않고 promise 자체를 리턴 해서 병렬 요청.
     const artistData = getArtist(username);
     const albumData = getArtistAlbums(username);

     // Wait for the artist's promise to resolve first
     const artist = await artistData;

     return (
       <>
         <h1>{artist.name}</h1>
         {/* Send the artist information first, and wrap albums in a suspense boundary */}
         <Suspense fallback={<div>Loading...</div>}>
           <Albums promise={albumData} />
         </Suspense>
       </>
     );
   }

   // Albums Component
   async function Albums({ promise }: { promise: Promise<Album[]> }) {
     // Wait for the albums promise to resolve
     const albums = await promise;

     return (
       <ul>
         {albums.map((album) => (
           <li key={album.id}>{album.name}</li>
         ))}
       </ul>
     );
   }
MinJeung-Kim commented 1 year ago

⚠️Error UI

import { useEffect } from 'react';

export default function Error({ error, reset, }: { error: Error; reset: () => void; }) { useEffect(() => { // Log the error to an error reporting service console.error(error); }, [error]);

return (

Something went wrong!

); }



### 중첩된 레이아웃에서 Error
- 만약 dashboard폴더에 error.js가 없다면 상위 error.js를 보여줌.
![image](https://github.com/MinJeung-Kim/NextJS-v13--Study/assets/79193369/929853f8-2616-4bbc-a72d-bccde9e2af63)
MinJeung-Kim commented 1 year ago

🎥<Image /> 태그

import MeowArticle from "@/components/MeowArticle";
import { getProducts } from "@/service/products";
import Image from "next/image"; 
import clothesImage from "public/images/clothes.jpg";

export default async function ProductsPage() { 

  return ( 
      {/* 경로보다는 로컬에 있으므로 Static하게 import하는게 좋음. */}
      <Image src={clothesImage} alt="Clothes" /> 
  );
}

외부 경로 사용 방법

module.exports = nextConfig;

MinJeung-Kim commented 1 year ago

🔡Fonts

// app/layout.tsx

import { Open_Sans } from "next/font/google";
import { Nanum_Gothic } from "next/font/google";

const sans = Open_Sans({ subsets: ["latin"] });
const gothic = Nanum_Gothic({
  weight: "700",
  subsets: ["latin"],
}); 

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" className={sans.className}>
      <body>
        <header className={styles.header}>
          <h1 className={gothic.className}>Demo Note</h1> 
        </header>
        {children}
      </body>
    </html>
  );
}

chrome_jjXhyqhihF