exportasyncfunctiondeleteInvoice(id:string) {try {awaitsql`DELETE FROM invoices WHERE id = ${id}`;revalidatePath('/dashboard/invoices');return { message:'인보이스가 삭제되었습니다.' }; } catch (error) {return { message:'데이터베이스 오류: 인보이스 삭제에 실패했습니다.' }; }}
redirect가 try/catch 블록 외부에서 호출되는 것을 주목하세요. 이는 redirect가 에러를 던지는 방식으로 작동하기 때문에 catch 블록에서 잡힐 것입니다. 이를 피하기 위해 try/catch 이후에 redirect를 호출할 수 있습니다. redirect는 try가 성공했을 때에만 도달 가능합니다.
이제 서버 액션에서 에러가 발생했을 때의 동작을 확인해보겠습니다. 이를 위해 이전보다 더 일찍 에러를 던져서 확인할 수 있습니다. 예를 들어, deleteInvoice 액션에서 함수 상단에 에러를 던져보세요:
/app/lib/actions.ts
exportasyncfunctiondeleteInvoice(id:string) {thrownewError('인보이스 삭제에 실패했습니다.');// 도달할 수 없는 코드 블록try {awaitsql`DELETE FROM invoices WHERE id = ${id}`;revalidatePath('/dashboard/invoices');return { message:'인보이스가 삭제되었습니다.' }; } catch (error) {return { message:'데이터베이스 오류: 인보이스 삭제에 실패했습니다.' }; }}
인보이스를 삭제하려고 시도하면 로컬호스트에서 에러가 표시될 것입니다.
이러한 에러는 개발 중에 잠재적인 문제를 조기에 발견할 수 있어 도움이 됩니다. 하지만 갑작스러운 실패를 피하고 애플리케이션을 계속 실행할 수 있도록 사용자에게 에러를 표시하고 싶을 것입니다.
이것은 error.tsx가 정의되어있는 /invoices의 자식 라우트이기 때문에 error.tsx가 바로 튀어나오는 것을 바로 확인할 수 있습니다.
그러나 좀 더 구체적으로 처리하고 싶다면, 사용자에게 접근하려는 리소스가 찾을 수 없음을 알려주기 위해 404 에러를 표시할 수 있습니다.
data.ts의 fetchInvoiceById 함수로 이동하고 반환된 송장을 콘솔에서 기록하여 리소스를 찾지 못했음을 확인할 수 있습니다.:
/app/lib/data.ts
exportasyncfunctionfetchInvoiceById(id:string) {noStore();try {// ...console.log(invoice); // 인보이스는 빈 배열입니다 []return invoice[0]; } catch (error) {console.error('데이터베이스 오류:', error);thrownewError('인보이스를 가져오는 데 실패했습니다.'); }}
이제 데이터베이스에 인보이스가 존재하지 않음을 알게 되었습니다. 이를 처리하기 위해 notFound를 사용해봅시다. /dashboard/invoices/[id]/edit/page.tsx로 이동하고 'next/navigation'에서 { notFound }를 import하세요.
그런 다음, 인보이스가 존재하지 않는 경우 notFound를 호출할 수 있는 조건문을 사용할 수 있습니다: