최종 프로젝트를 진행하면서 유저 정보를 가져올 때 유저 정보가 없을시의 에러처리를 어떻게 처리할지 고민하는 도중에 Next.js의 docs에서 server action에서 try catch를 추천하지 않는다고 하는 것을 보게 되었다.
본문에 따르면 에러는 예상되는 에러와 잡히지 않는 예외상황 두 가지로 나눌 수 있다고한다.
예상되는 에러처리는 서버사이드에서의 form 유효성 검사 또는 요청 실패와 같이 어플리케이션의 정상적인 작동 중 발생할 수 있는 오류인데 이런 오류는 명시적으로 처리해서 클라이언트에 반환을 해야한다고 한다.
예시)
'use server'
import { redirect } from 'next/navigation'
export async function createUser(prevState: any, formData: FormData) {
const res = await fetch('https://...')
const json = await res.json()
if (!res.ok) {
return { message: 'Please enter a valid email' }
}
redirect('/dashboard')
}
에러처리를 포함해서 서버 작업 상태를 관리할 때는 useFormState
훅을 사용하고 이 접근 방식은 try/catch문을 사용하지 않고 예외처리가 아닌 에러를 return해주는 식으로 모델링해야한다.
'use client'
import { useFormState } from 'react'
import { createUser } from '@/app/actions'
const initialState = {
message: '',
}
export function Signup() {
const [state, formAction] = useFormState(createUser, initialState)
return (
<form action={formAction}>
<label htmlFor="email">Email</label>
<input type="text" id="email" name="email" required />
{/* ... */}
<p aria-live="polite">{state?.message}</p>
<button>Sign up</button>
</form>
)
}
이후 useFormState에 action을 통과시키고 state를 return받아서 error 메세지를 출력한다. 이 방식으로 taost message또한 display할 수 있다.
export default async function Page() {
const res = await fetch(`https://...`)
const data = await res.json()
if (!res.ok) {
return 'There was an error.'
}
return '...'
}
서버 컴포넌트에서도 data를 fetching할 때 response에 조건부로 에러 메세지나 redirect를 return하는 것을 추천하고 있다.
본문을 보니까 우리가 예측할 수 있는 에러들은 클라이언트 상에서 따로 메세지를 보여주도록 하거나 redirect를 하는 방향을 추천을 하고 있고 예상치 못한 에러일 경우에만 에러 바운더리에서 error.tsx나 global-error.tsx같은 fallback ui를 통해 처리하는 것을 의도하는 것 같다.
에러처리 참 어렵다... 어떤 에러들을 명시적으로 처리해야할지도 기획 단계에서 해야 에러처리가 쉬운 방향일 것 같다. 명시적으로 넘겨서 처리할 수 있는 것들은 굳이 error boundary로 넘길 필요가 없는 것일까? 만약 server action에서 에러를 throw한다면 error boundary로 넘어갈 것이고 여기서 reset과 refresh를 했을 때 try catch가 이를 방해 할 수 도 있고 중복된 에러처리가 될 수도 있어서 그런 것 같기도 하다.