Loading...
본문 바로가기
👥
총 방문자
📖
0개 이상
총 포스팅
🧑
오늘 방문자 수
📅
0일째
블로그 운영

여러분의 방문을 환영해요! 🎉

다양한 개발 지식을 쉽고 재미있게 알려드리는 블로그가 될게요. 함께 성장해요! 😊

코딩 정보/NextJs

[NextJs] 캐싱에 대해 더 자세히 알아보자

by 꽁이꽁설꽁돌 2025. 4. 15.
728x90
반응형
     

목차

     

     

     

     

    중복된 요청에 대한 NextJs의 처리

    아래와 같이 api를 요청하면 api의 헤더 값이 달라 각 요청을 모두 받는다.

    export default async function MessagesLayout({ children }) {
      const response = await fetch('http://localhost:8080/messages', {
        headers: {
          'X-ID': 'layout',
        },
      });
      const messages = await response.json();
      const totalMessages = messages.length;
    
      return (
        <>
          <h1>Important Messages</h1>
          <p>{totalMessages} messages found</p>
          <hr />
          {children}
        </>
      );
    }

     

    import Messages from '@/components/messages';
    
    export default async function MessagesPage() {
      const response = await fetch('http://localhost:8080/messages', {
        headers: {
          'X-ID': 'page',
        },
      });
      const messages = await response.json();
    
      if (!messages || messages.length === 0) {
        return <p>No messages found</p>;
      }
    
      return <Messages messages={messages} />;
    }

     

     

     

    이런식으로 두 url을 수정해주면 중복된 요청이므로 next가 알아서 한번만 가져오게 된다.

     const response = await fetch("http://localhost:8080/messages");

     

     

     

    캐싱 설정하기

    next15 버전은 캐싱 설정을 해줘야 캐싱이 된다. 따라서 아래와 같이 설정하게 되면 10초마다 캐싱을 최신화 시킨다.

    이때 개발환경에서는 적용이 되지 않으므로 주의하자 

    import Messages from "@/components/messages";
    
    export default async function MessagesPage() {
      const response = await fetch("http://localhost:8080/messages",{next:{revalidate: 10}});
      const messages = await response.json();
    
      if (!messages || messages.length === 0) {
        return <p>No messages found</p>;
      }
    
      return <Messages messages={messages} />;
    }

     

     

    계속 새로고침을 했을 때 10초가 지나 api 요청이 진행된 모습

     

    그외에도 cache: 'no-store', cache: 'force-cache' 등 여러 옵션이 있다.

     

    캐싱 제어의 다른 방법들

     

    unsable_noStore()  함수 사용하기

    import { unstable_noStore } from "next/cache";
    import Messages from "@/components/messages";
    
    
    export default async function MessagesPage() {
      //확실하게 캐싱을 안하고자 하는 컴포넌트에 호출
      unstable_noStore();
      const response = await fetch("http://localhost:8080/messages");
      const messages = await response.json();
    
      if (!messages || messages.length === 0) {
        return <p>No messages found</p>;
      }
    
      return <Messages messages={messages} />;
    }

     

     

    export const revalidate 사용

    {next:{revalidate: 5}} 옵션과 같은 기능을 한다. (똑같은데 왜 여러개 있는지 모르겠음)

    import Messages from "@/components/messages";
    
    export const revalidate =5;
    
    export default async function MessagesPage() {
    
      const response = await fetch("http://localhost:8080/messages");
      const messages = await response.json();
    
      if (!messages || messages.length === 0) {
        return <p>No messages found</p>;
      }
    
      return <Messages messages={messages} />;
    }

     

    export const dynamic 사용

    파일 내 데이터를 항상 가져오게 만들 때 사용한다. (= 'no-cache')

    import Messages from "@/components/messages";
    
    
    //파일 내 데이터를 항상 가져오게
    export const dynamic = "force-dynamic";
    
    export default async function MessagesPage() {
    
      const response = await fetch("http://localhost:8080/messages");
      const messages = await response.json();
    
      if (!messages || messages.length === 0) {
        return <p>No messages found</p>;
      }
    
      return <Messages messages={messages} />;
    }

     

    이때 빌드 시에는 동적 페이지를 제외한 페이지들은 미리 생성된 상태로 만들어지게 된다.

    아래에서 force-dynamic 설정을 한message를 보게 되면 동적으로 바뀐 것을 볼 수 있다.  

     

     

    revalidateTag 사용하기

    import Messages from "@/components/messages";
    
    
    export default async function MessagesPage() {
    
      const response = await fetch("http://localhost:8080/messages",{
        next: {tags: ['msg']}
      });
      const messages = await response.json();
    
      if (!messages || messages.length === 0) {
        return <p>No messages found</p>;
      }
    
      return <Messages messages={messages} />;
    }
    import { redirect } from "next/navigation";
    
    import { addMessage } from "@/lib/messages";
    import { revalidateTag } from "next/cache";
    
    export default function NewMessagePage() {
      async function createMessage(formData) {
        "use server";
    
        const message = formData.get("message");
        addMessage(message);
        revalidateTag("msg");
        redirect("/messages");
      }
    
      return (
        <>
          <h2>New Message</h2>
          <form action={createMessage}>
            <p className="form-control">
              <label htmlFor="message">Your Message</label>
              <textarea id="message" name="message" required rows="5" />
            </p>
    
            <p className="form-actions">
              <button type="submit">Send</button>
            </p>
          </form>
        </>
      );
    }

     

     

    api를 사용하지 않고 db 접근 코드만 사용했을 때 중복 요청 막기

    중복 요청이 일어난다.

     

    cache 사용

    import sql from "better-sqlite3";
    import { cache } from "react";
    
    export const getMessages = cache(function getMessages() {
      console.log("Fetching messages from db");
      return db.prepare("SELECT * FROM messages").all();
    });

     

    아래의 두 코드에서 중복 요청이 사라지게 된다.

    import Messages from "@/components/messages";
    import { getMessages } from "@/lib/messages";
    
    export const dynamic = "force-dynamic";
    
    export default function MessagesPage() {
    
      const messages = getMessages();
    
      if (!messages || messages.length === 0) {
        return <p>No messages found</p>;
      }
    
      return <Messages messages={messages} />;
    }

     

    import { getMessages } from "@/lib/messages";
    
    export default function MessagesLayout({ children }) {
      const messages = getMessages();
      const totalMessages = messages.length;
    
      return (
        <>
          <h1>Important Messages</h1>
          <p>{totalMessages} messages found</p>
          <hr />
          {children}
        </>
      );
    }

     

    중복 요청이 사라진 모습

     

     

    api를 사용하지 않고 db 접근 코드만 사용했을 때 캐싱하기

    import sql from "better-sqlite3";
    import { cache } from "react";
    import { unstable_cache } from "next/cache";
    
    export const getMessages = unstable_cache(
      cache(function getMessages() {
        console.log("Fetching messages from db");
        return db.prepare("SELECT * FROM messages").all();
      }),
      ["messages"] //캐싱 식별을 위한 배열
    );

     

    프로미스를 반환하므로 다음과 같이 await를 추가하고 async로 수정해 주어야 한다.

    import { getMessages } from "@/lib/messages";
    
    export default async function MessagesLayout({ children }) {
    
      const messages = await getMessages();
      const totalMessages = messages.length;
    
      return (
        <>
          <h1>Important Messages</h1>
          <p>{totalMessages} messages found</p>
          <hr />
          {children}
        </>
      );
    }
    import Messages from "@/components/messages";
    import { getMessages } from "@/lib/messages";
    
    export const dynamic = "force-dynamic";
    
    export default async function MessagesPage() {
    
    
      const messages = await getMessages();
    
      if (!messages || messages.length === 0) {
        return <p>No messages found</p>;
      }
    
      return <Messages messages={messages} />;
    }

     

     

    반응형