폼 유효화가 필요하다.
어떻게 서버액션으로 서버 사이드 검증를 하는지와, 리액트의 useActionState 훅을 통해 에러를 보여주는지 배워보자
접근성 향상을 위해 Next.js와 eslint-plugin-jsx-a11y 를 사용하는 법
서버 사이드 폼 유효성 검사를 하는 법
폼 에러를 처리하고 사용자에게 보여주기 위해 리액트 useActionState 훅을 쓰는 법
모두가 사용할 수 있는 웹 디자인 및 구현을 가리킴
키보드 네비게이션, 시멘틱 태그, 이미지 등 다양한 주제를 내포함
이번 챕터에선 Next.js에서 가능한 접근성의 특징을 배우고 몇 실습을 한다.
디폴트로 Next.js는 eslint-plugin-jsx-a11y 플러그인을 갖고 있어 법근성 이슈를 잡는 걸 도운다.
예시로, 이 플로그인은 이미지를 alt 없이 입력 시, aria-* and role 를 잘못되게 사용한다.
"lint": "next lint",
를 패키지.json에 추가한다.
그리고 pnpm lint를 실행한다. (내 경우에는 npm run lit)

다음 메시지를 볼 수 있다.
그러나 이미지를 alt 없이 넣는다면?
/app/ui/invoices/table.tsx로 가서 alt를 지운다.
lint 재실행 시 다음과 같은 문구가 뜬다.

만약 vercel로 앱 배포 시, 경고는 빌드 로그에서 뜰 것이다.
이것은 next lint가 빌드 과정의 일부분이기 때문이다.
따라서 배포 전에 접근성 이슈를 잡기 위해 lint를 실행할 수 있다.
접근성 향상을 위해 이미 하고 있는 것들
위 사례들은 접근성 향상에 좋지만, 폼 유효성 검사와 에러는 안 다룬다.
http://localhost:3000/dashboard/invoices/create 에서 빈 폼을 제출한다면?
=> 에러가 난다. 서버 액션에 빈 폼 값을 보내기 때문이다. 이것을 클라이언트 혹은 서버에서 검증을 통해 방지할 수 있다.
몇 가지 방법 중 가장 간단한 것은 인풋과 select 요소에 required를 추가하는 것이다.
<input
id="amount"
name="amount"
type="number"
placeholder="Enter USD amount"
className="peer block w-full rounded-md border border-gray-200 py-2 pl-10 text-sm outline-2 placeholder:text-gray-500"
required
/>
다시 폼 제출 시, 경고를 볼 수 있다.
이 접근 역시 AT가 브라우저 유효성 검사를 하므로 괜찮다.
클라이언트 사이드 검증의 대안은 서버 사이드 검증이다.
이제 다시 required를 지운다.
서버에서 검증 하기 위해 다음이 필요하다.
create-form.tsx 컴포넌트에서, useActionState를 불러온다.
useActionState가 훅이기에, 폼을 'use client';를 통해 클라이언트 컴포넌트로 바꾼다.
폼 컴포넌트 안에서 useActionState 훅은 :
useActionState에 argu로서 createInvoice 를 넘기고
폼 액션 어트리뷰트에서 formAction을 호출한다.
initialState는 정의하는 모든 것이 될 수 있다.
이 경우에는, 두개의 빈 키: message, errors로 객체를 생성하고 actions.ts에서 State를 불러온다.
action.ts 에서, 검증을 위해 Zod를 쓸 수 있다.
FormSchema를 다음과 같이 고친다.
이제 createInvoice 액션이 두 개의 파라미터를 받도록 갱신하자 : prevState, formData
그 후, Zod parse( )를 safeParse()로 고친다. 이것은 success | error 필드를 포함하는 객체이다.
DB에 정보 전송 전에, 폼 필드가 검증됐는지를 조건문으로 확인하자
if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
message: 'Missing Fields. Failed to Create Invoice.',
};
}
만약 validatedFields가 성공적이 아니라면, Zod로 만든 에러 메시지를 반환하는 함수를 만난다.
마침내, 유효성을 try/catch 블럭 밖에서 구분지어 핸들링 했으므로, 어느 db 에러던 특정 메시지를 추가할 수 있다.
이제 에러를 폼 컴포넌트에 추가하자
create-form.tsx로 들어가 폼 state를 통해 에러에 접근할 수 있다.
특정 각 에러를 검사하는 삼항 연산자를 추가하자.
<div id="customer-error" aria-live="polite" aria-atomic="true">
{state.errors?.customerId &&
state.errors.customerId.map((error: string) => (
<p className="mt-2 text-sm text-red-500" key={error}>
{error}
</p>
))}
</div>
폼이 비었을 때 밑에 에러 메시지를 나타내자
