티스토리 뷰

1. 개요

 캐싱은 성능 최적화와 사용자 경험 개선에 있어 중요하다. 왜냐하면 캐시를 사용하는 것으로 반복적인 요청을 줄이고, 서버의 부하를 낮출 수 있으며 사용자에게 보다 빠르고 일관적인 데이터를 제공할 수 있기 때문이다. 예를 들어 아래와 같이 상품의 상세 정보를 보여주는 페이지가 있다고 하자.

 

// 상품의 상세 정보를 받아오는 함수
async function getProduct(id: number) {
  console.log("getProduct!!!");

  const product = await db.product.findUnique({
    where: {
      id,
    },
    include: {
      user: {
        select: {
          username: true,
          avatar: true,
        },
      },
    },
  });

  return product;
}

// 메타데이터를 위한 title을 받아오는 함수
const getProductTitle = async (id: number) => {
  console.log("getProductTitle!!!");

  const product = await db.product.findUnique({
    where: {
      id,
    },
    select: { title: true },
  });

  return product;
};

 

 

여기서 상품의 정보를 불러오는 함수와 메타데이터를 위해 정보를 불러오는 함수가 2개가 있다. 이 때, 새로고침을 계속 누르면 상품의 정보가 변한 것이 없더라도 같은 요청을 계속 시도한다.

 

 

물론 로컬 개발 환경에서는 크게 문제가 없지만 실제 상황에서는 사용자에게 좋지 않은 경험을 남겨줄 수도 있다. 그렇기에 필요없는 요청을 방지하기 위한 방법 중 캐싱이라는 것이 있는데, 이를 적용해보려 한다.

 

2. revalidate

 우선 Next.js에서 캐싱을 이용하기 위해서는 use cache를 이용할 수 있다. 하지만 이 글은 노마드 코더 강의에서 배운 unstable_cache에 대해 기록하는 글이기에 여기서는 unstable_cache를 이용하려 한다. (unstable_cache는 공식 문서에서 legacy api라고 한다.) unstable_cache는 첫 번째 인자로 api 요청을 하는 함수를, 두 번째 인자로는 해당 함수의 결과를 유니크하게 구별할 수 있는 key값을 담은 배열이 필요하다.

 

const getCachedProduct = nextCache(getProduct, ["product-detail"]);
const getCachedProductTitle = nextCache(getProductTitle, ["product-title"]);

 

그리고 세 번째 인자로는 캐싱 옵션을 넣을 수 있다. validate라는 옵션은 데이터를 저장하고 있는 시간, 즉 만료 기간을 초 단위로 설정할 수 있다. 예를 들어, { validate: 30 }으로 설정하면 30초동안 캐싱하고 있는다는 의미이다.

 

const getCachedProduct = nextCache(getProduct, ["product-detail"], {
  revalidate: 10,
});
const getCachedProductTitle = nextCache(getProductTitle, ["product-title"], {
  revalidate: 10,
});

 

 

validate를 10(10초)으로 설정한 후, 계속 새로고침을 해보았다. 그리고 실제로 10초 후에 새로 고침을 하니 다시 데이터를 받아오는 것을 확인할 수 있었다.

 

3. revalidatePath

 revalidatePath특정 path에 연결되어 있는 모든 데이터를 새로고침할 수 있는 방법이다. 이는 버튼 등과 연결해서 직접 실행할 수 있다.

 

const getCachedProduct = nextCache(getProduct, ["product-detail"], {})
const getCachedProductTitle = nextCache(getProductTitle, ["product-title"]);

... 생략

export default async function ProductDetail({
  params,
}: {
  params: { id: string };
}) {
... 생략

  const revalidate = async () => {
    "use server";

    revalidatePath("/products/5");
  };
  
  return (
    <div className="pb-40">
    ... 생략
      <div>
        {isOwner ? (
          <form action={revalidate}>
            <button className="bg-red-500 px-5 py-2.5 rounded-md text-white font-semibold">
              Revalidate title cache
            </button>
          </form>
        ) : null}
      </div>
    </div>
  );
}

 

revalidate라는 함수를 생성한 후, revalidatePath에 "/products/5"라는 path를 인자로 주었다. 현재 확인해볼 상품의 id가 5이기에 편의상 하드코딩으로 작성하였다.

 

 

새로고침을 계속 해도 api를 요청하는 함수가 실행되지 않다가 ravalidate라는 함수를 동작시키게 하는 버튼을 클릭하였더니 현재 path(/products/5)와 연결되어 있던 두 함수가 다시 실행되는 것을 확인할 수 있었다.

 

4. revalidateTags

 마지막은 revalidateTags로, path 대신 작성한 tags가 설정된 함수들을 다시 받아오게 할 수 있는 방법이다. 

 

const getCachedProduct = nextCache(getProduct, ["product-detail"], {
  tags: ["product-detail", "xxx"],
});
const getCachedProductTitle = nextCache(getProductTitle, ["product-title"], {
  tags: ["product-title", "xxx"],
});

... 생략

export default async function ProductDetail({
  params,
}: {
  params: { id: string };
}) {
... 생략

  const revalidate = async () => {
    "use server";

    revalidateTag("product-detail");
  };
  
  return (
    <div className="pb-40">
    ... 생략
      <div>
        {isOwner ? (
          <form action={revalidate}>
            <button className="bg-red-500 px-5 py-2.5 rounded-md text-white font-semibold">
              Revalidate title cache
            </button>
          </form>
        ) : null}
      </div>
    </div>
  );
}

 

getChacedProduct는 tag로 product-detail, xxx를, getCachedProductTitle은 tag로 product-title, xxx를 가지고 있다. 그리고 revalidate라는 함수는 product-detail라는 tag만 다시 불러오게 한다.

 

 

버튼을 클릭한 순간, product-detail라는 tag를 가지고 있는 getChacedProduct의 getProductTitle만 다시 실행되는 것을 확인할 수 있다.

 

5. fetch 함수에서는

const testFunc = async () => {
  fetch("https://~~~", {
    next: {
      revalidate: 60,
      tags: ["test-tag"],
    },
  });
};

 

 위 함수들은 Prisma를 이용한 함수들이었다. 그리고 외부 api를 이용할 경우에는 위 코드처럼 next라는 옵션에서 revalidate, tags 등을 설정할 수 있다.

 


unstable-cache: https://nextjs.org/docs/app/api-reference/legacy-apis/unstable_cache

 

Legacy APIs: unstable_cache | Next.js

API Reference for the unstable_cache function.

nextjs.org

 

use-cache: https://nextjs.org/docs/app/api-reference/directives/use-cache 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함