Uncontrolled Components
: 폼 요소의 상태를 제어하지 않는 컴포넌트
한마디로 정의하자면 과정은 보지 않고 결과만 반영하여준다.(마지막 제출할때만)
즉 코드상으로 onChage 등으로 관리할 필요가 없다는것!
장점 :
- 간단한 구현 - 상태를 따로 관리하지 않기 때문에 간단한 폼 처리에 적합하다
- 낮은 복잡성 - 폼의 상태를 리액트 상태로 동기화할필요가 없음으로 상태를 관리하지 않아도 된다
단점 :
- 비제어 컴포넌트이니까 당연하게도 제어되지 않는다 -> 폼의 상태 추적이나 제어가 어려울 수 있다.
- 복잡한 폼 처리 어려움 : 실시간 유효성 검사 불가 : 판단하려면 무조건 제출해야함
FormData
https://ko.javascript.info/formdata
FormData 객체
ko.javascript.info
https://developer.mozilla.org/ko/docs/Web/API/FormData
FormData - Web API | MDN
FormData 인터페이스는 form 필드와 그 값을 나타내는 일련의 key/value 쌍을 쉽게 생성할 수 있는 방법을 제공합니다. 또한 XMLHttpRequest.send() 메서드를 사용하여 쉽게 전송할 수 있습니다. 인코딩 타입
developer.mozilla.org
장점 :
- 이름부터 FormData로, 직관적으로 코드를 작성하기 때문에 가독성이 좋다
- reset등 메서드 지원으로 쉬운 폼 제어가 가능하다.
코드예시
value, onChange함수 없이도 가능하다.
export default function TodoForm({ fetchTodos }: TodoFormProps) {
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget); //FormData 생성
const title = formData.get('title')?.toString().trim(); //인풋의 value값을 가져올수있음
await createTodo({ title }); // Todo 추가
e.currentTarget.reset(); // 폼 초기화
}
};
return (
<form onSubmit={handleSubmit}>
<input name="title" type="text" placeholder="할 일을 입력하세요" />
<button type="submit">추가하기</button>
</form>
);
}
Next.js만 활용해서 CRUD 구현하기
CREATE - 생성
새로운 항목추가 : POST 요청 : 데이터를 전송 > 새 항목 생성
// api/todo-api.ts
export const createTodo = async (title: string) => {
const res = await fetch('/api/todos', {
method: 'POST', // 새로운 리소스를 생성할 때 사용
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, completed: false }), // 전송할 데이터를 JSON 형태로 변환
});
if (!res.ok) throw new Error('Todo 생성 실패');
const data: Todo = res.json(); // 생성된 Todo 데이터 반환
return data;
};
🤔 headers: { 'Content-Type': 'application/json' } 의 역할
body에서 JSON.stringfy로 문자열로 만들어 보내주었기 때문에, 서버는 문자열만 받기때문에 알수가 없는데, 헤더에서 { 'Content-Type': 'application/json' } json형태라고 알려주었기때문에 서버는 이 헤더를 보고 JSON형태의 데이터를 받을 준비를 할수 있다.
🤔 res.json()쓰는이유
응답이 ReadableStream 형태로 제공된다. 이 스트림 데이터는 바로 사용할수 없고, 텍스트나 객체로 변환해야하기때문에,
응답받은 제이슨 데이터를 .json()으로 자바스크립트 객체로 변환하여 주어야 한다.
DELETE - 삭제
// api/todo-api.ts
export const deleteTodo = async (id: string) => {
const res = await fetch(`/api/todos/${id}`, {
method: 'DELETE', // DELETE 메서드는 특정 리소스를 삭제할 때 사용
});
if (!res.ok) throw new Error('삭제 실패');
};
UPDATE - 수정
// api/todo-api.ts
export const toggleTodoCompleted = async (id: string, completed: boolean) => {
const res = await fetch(`/api/todos/${id}`, {
method: 'PATCH', // PATCH 메서드는 리소스의 일부 데이터를 수정할 때 사용
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ completed }), // 변경할 데이터 전달
});
if (!res.ok) throw new Error('업데이트 실패');
const data: Todo = res.json(); // 업데이트된 Todo 데이터 반환
return data;
};
하지만 이렇게 구현했을때 문제점이 있다.
추가/삭제/수정 시에 바로바로 화면에 뜨지않고 새로고침을 해야 반영이되는데
즉, 리 랜더링이 일어나지 않는 이상 브라우저에 적용이 되지 않는다. 이문제를 어떻게 해결할수 있을까?
서버 액션 및 캐시 revalidate 활용
서버 액션은 Next.js에서 서버에서 직접 데이터를 처리할 수 있도록 도와주는 기능으로, 기존의 라우트 핸들러를 사용하지 않고도 서버의 함수를 직접 호출하여 데이터를 변경할 수 있다.
서버 액션을 사용하는 이유:
- 코드 간소화: 라우트 핸들러를 따로 생성하지 않아도 되므로 코드가 단순해짐
- 직접적인 데이터베이스 작업: 서버에서 직접 데이터베이스와 상호작용하여 효율성을 높일 수 있음
- 보안 강화: 클라이언트에서 민감한 API 요청을 직접 노출하지 않고 서버에서 처리할 수 있음
- 자동 데이터 갱신: revalidatePath 또는 revalidateTag를 활용하여 변경된 데이터를 자동으로 최신 상태로 유지할 수 있음
'use server';
// 서버에서 직접 데이터 변경 작업을 처리
export const deleteTodoAction = async (id: string) => {
await fetch(`http://localhost:3000/api/todos/${id}`, { method: 'DELETE' });
revalidatePath('/todos'); // 특정 경로('/todos')를 자동으로 갱신
// 또는
revalidateTag('todos'); // 태그 기준으로 자동 갱신
};
- 'use server'; 코드 추가
- revalidatePath 또는 revalidateTag 로 갱신요청 > 서버에서 자동으로 갱신해줌
컴포넌트에서 호출하기
'use client';
import { deleteTodoAction } from '@/actions/deleteTodoAction';
export default function TodoItem({ todo }) {
const handleDelete = () => {
deleteTodoAction(todo.id);
};
return (
<div>
<span>{todo.title}</span>
<button onClick={handleDelete}>삭제</button>
</div>
);
}'Next.js' 카테고리의 다른 글
| as="link"? 왜 작동 안 하는지 (1) | 2025.04.14 |
|---|---|
| 쿠키가 존재하면 로그인 상태라고 할수있는가? (0) | 2025.04.05 |
| App Router VS Pages Router (0) | 2025.03.17 |
| 서버 컴포넌트 vs 클라이언트 컴포넌트 (0) | 2025.03.11 |
| Next.js App Router에서의 렌더링 방식 이해하기 (1) | 2025.03.10 |