기록
Next.js의 서버 액션에서 발생한 "It is not allowed to define inline 'use server'..." 에러 해결하기
als982001
2024. 11. 24. 16:15
1. 개요
버튼을 클릭하면 해당 상품의 간단한 정보를 모달로 보여주는 기능을 구현하려고 했다. 그래서 이를 위해 다음과 같이 코드를 작성했다.
// components/ProductModal.tsx
import { useEffect, useState } from "react";
import { PhotoIcon } from "@heroicons/react/24/solid";
import db from "@/lib/db";
interface IProps {
id: number;
handleShoWModal: (e: React.MouseEvent) => void;
}
export default function ProductModal({ id, handleShoWModal }: IProps) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [product, setProduct] = useState<any>(null);
const [isLoading, setIsLoading] = useState(true);
async function getProduct(id: number) {
try {
const product = await db.product.findUnique({
where: {
id,
},
include: {
user: {
select: {
username: true,
avatar: true,
},
},
},
});
return product;
} catch (e) {
console.error(e);
return null;
}
}
useEffect(() => {
(async () => {
const product = await getProduct(id);
setProduct(product);
setIsLoading(false);
})();
}, [id]);
if (isLoading) {
return (
<div
className="absolute w-full h-full z-50 flex items-center justify-center bg-black bg-opacity-60 left-0 top-0"
onClick={handleShoWModal}
>
<div className="max-w-screen-sm h-1/2 flex justify-center w-full">
<div className="aspect-square bg-neutral-700 text-neutral-200 rounded-md flex justify-center items-center">
<PhotoIcon className="h-28" />
</div>
</div>
</div>
);
}
if (!product) {
return <div>없음</div>;
}
console.log(product);
return <div>{`id: ${id}`}</div>;
}

Error: PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in unknown). If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report
ProductModal이라는 컴포넌트의 부모 컴포넌트는 클라이언트이다. 그렇기에 위와 같은 에러가 발생했다. 이는 PrismaClient가 브라우저 환경에서 실행되었거나 브라우저를 대상으로 번들링되었을 때 발생하는 에러로, 서버 환경이 아닌 곳에서 실행하려 했기에 발생한 에러이다. 그래서 이를 수정하려 했다.
2. 에러 발생
// components/ProductModal.tsx
import { useEffect, useState } from "react";
import { PhotoIcon } from "@heroicons/react/24/solid";
import { getProduct } from "@/lib/product";
interface IProps {
id: number;
handleShoWModal: (e: React.MouseEvent) => void;
}
export default function ProductModal({ id, handleShoWModal }: IProps) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [product, setProduct] = useState<any>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
(async () => {
const product = await getProduct(id);
setProduct(product);
setIsLoading(false);
})();
}, [id]);
if (isLoading) {
// return 스켈레톤 컴포넌트
}
if (!product) {
// return 상품 정보 없음
}
// return 상품 정보
}
// lib/product.ts
import db from "./db";
export async function getProduct(id: number) {
"use server";
try {
const product = await db.product.findUnique({
where: {
id,
},
include: {
user: {
select: {
username: true,
avatar: true,
},
},
},
});
return product;
} catch (e) {
console.error(e);
return null;
}
}
"use server"라는 코드를 추가하는 것으로 서버 액션을 사용할 수 있다고 배웠기에 위와 같이 코드를 작성하였다.

그랬더니 위 이미지처럼 에러가 발생하였다.
3. 원인
Next.js의 서버 액션(Server Action)은 특정 규칙을 따른다.
- "use server"는 파일 최상단에 선언되어야 한다.
- 클라이언트 컴포넌트 내부에서는 "use server"를 사용하여 서버 액션을 정의할 수 없다.
- 서버 액션은 클라이언트 컴포넌트에서 직접 실행할 수 없으며 RPC(Remote Procedure Call) 형태로 호출된다.
즉, "use server"를 최상단에 선언하지 않았기 때문에 발생한 에러였다. 그렇기에 아래 코드처럼 수정하여 에러를 해결할 수 있었다.
"use server";
import db from "./db";
export async function getProduct(id: number) {
try {
const product = await db.product.findUnique({
where: {
id,
},
include: {
user: {
select: {
username: true,
avatar: true,
},
},
},
});
return product;
} catch (e) {
console.error(e);
return null;
}
}
관련 문서
- Next.js Server Actions 공식 문서: https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations