next13.4에서 server action이라는 실험적 기능이 생겼다.
사실 13버전 이전의 버전은 사용해본 적이 없기 때문에 어디가 더 나아진 건지 알지 못한다. 그냥 배울 뿐...ㅋ
server action에 관한 내용이 많지 않아 100% 이해하진 못했다.
한국어로 된 설명도 아직도 뭐가 뭔지 모르겠다.
영어로 된 유튜브 설명을 듣고 번역하고 해서 대충 알아듣는 정도...
써보면서 이해한다.
DB에 데이터를 저장하고 싶으면 서버를 거치는데
그러기 위해 서버 파일을 만들어 API를 작성하고 뭐하고 번거로울 때
page.js안에서 해결할 수 있음.
const nextConfig = {
// 서버액션
experimental: {
serverActions: true,
}
}
그리고 서버로 전송할 데이터를 입력할 form을 넣어줌.
tailwind CSS로 대충 스타일을 줘봄.
form에 action은 {}로 폼 전송시 실행되는 함수 넣어줄 거임!
export default async function Home() {
return (
<main>
<h1 className="text-3xl font-bold text-center">
Product warehouse
</h1>
<form action={} className="flex flex-col gap-5 max-w-xl mx-auto p-5">
<input name="product" placeholder="상품의 이름을 입력해주세요" className="border border-gray-300 p-2 rounded-md" />
<input name="price" placeholder="상품의 가격을 입력해주세요" className="border border-gray-300 p-2 rounded-md" />
<button className="border bg-blue-500 text-white p-2 rounded-md">
상품 추가
</button>
</form>
</main>
)
}
mock API를 이용해서 product에 관한 더미 데이터를 fetch.
타입스크립트이기 때문에 상단에 데이터의 타입을 지정해주고
res.json()을 products에 넣어준다.
//2. 타입 지정
export interface Product {
id?: number;
product: string;
price: string;
}
export default async function Home() {
// 1. fetch data
const res = await fetch('https://각자의APIKEY.mockapi.io/products', {
cache: 'no-cache',
})
const products: Product[] = await res.json()
return (
<main>
<form action={} className="flex flex-col gap-5 max-w-xl mx-auto p-5">
//코드 생략....
</form>
//3. fetch data를 화면에 그림
<h2 className="font-bold p-5">List of Products</h2>
<div className="flex flex-wrap gap-5">
{products.map((product) => (
<div key={product.id} className="p-5 shadow">
<p>{product.product}</p>
<p>${product.price}</p>
</div>
))}
</div>
</main>
)
}
욜케 나옴
//1. async 함수로 작성해주고 함수 내부 상단에 'use server' 적어줌
const addProductToDatabase = async (e: FormData) => {
'use server'
// 4. 인풋의 내용을 문자열로 가져오기. 없으면 리턴한다.
const product = e.get('product')?.toString();
const price = e.get('price')?.toString();
if (!product || !price) return;
//5. 추가할 입력 값을 newProduct로 만들어준다.
const newProduct: Product = {
product,
price
};
// 6. api로 POST하기
await fetch('https://64fbf4fb605a026163ae172c.mockapi.io/products', {
method: 'POST',
body: JSON.stringify(newProduct),
headers: {
"Content-Type": 'application/json'
}
})
}
//2. action 에 함수이름 넣기
<form action={addProductToDatabase} className="flex flex-col gap-5 max-w-xl mx-auto p-5">
//3. input에 이름 주기
<input name="product" placeholder="상품의 이름을 입력해주세요" className="border border-gray-300 p-2 rounded-md" />
<input name="price" placeholder="상품의 가격을 입력해주세요" className="border border-gray-300 p-2 rounded-md" />
<button className="border bg-blue-500 text-white p-2 rounded-md">
상품 추가
</button>
</form>
위의 내용까지만 하면 network로 봤을 때 값은 잘 전송이 되었지만 ui화면에서 새로운 데이터를 추가한 내용은 적용되어 보여지지 않는다.
그걸 위해서는 tag를 사용하는데
처음 데이터를 fetch하는 함수에다가 아래와 같이 적어주고
form을 전송하는 함수 하단에 revalidateTag('products')적어주면
product가 업데이트 될 때마다 새로고침 하지 않아도 데이터를 다시 가져오게 된다.
const res = await fetch('https://64fbf4fb605a026163ae172c.mockapi.io/products', {
cache: 'no-cache',
next: {
tags: ['products']
}
})
const addProductToDatabase = async (e: FormData) => {
'use server'
//생략
await fetch('https://64fbf4fb605a026163ae172c.mockapi.io/products', {
method: 'POST',
body: JSON.stringify(newProduct),
headers: {
"Content-Type": 'application/json'
}
})
//태그
revalidateTag('products')
}
"allows server side mutations without unnecessary API endpoints"
"불필요한 API 엔드포인트 없이 서버 측 변이를 허용합니다."
서버 측에서 데이터 변경을 수행할 수 있고, 이를 위해 불필요한 API 엔드포인트를 만들 필요가 없는 기능 또는 아키텍처를 나타냅니다. 즉, 서버 측에서 데이터를 직접 조작하거나 업데이트할 수 있는 방법을 제공하며, API 엔드포인트를 최소화하거나 간소화할 수 있음을 의미.
"reduces the amount of client side javascript"
"클라이언트 측 자바스크립트 양을 줄입니다."
웹 애플리케이션의 클라이언트 측 코드인 자바스크립트 양을 감소시키는 효과
더 적은 클라이언트 측 자바스크립트 코드는 웹 페이지의 초기 로드 속도를 빠르게 하고, 사용자의 브라우저에서 실행되는 코드 양을 최소화하여 성능을 향상시킬 수 있다.
"supports progressively enhanced form"
"점진적으로 향상된(form) 형식을 지원합니다."
웹 폼(form)이 점진적으로 향상될 수 있는 방식을 지원.
웹 애플리케이션에서 폼 요소를 사용자 경험을 점진적으로 향상시키기 위해 더 많은 기능을 추가하는 것을 의미. 즉, 브라우저가 기본 기능을 제공하고, 그 후 JavaScript와 CSS 등을 사용하여 더 많은 기능을 추가할 수 있도록 하는 웹 접근성과 호환성을 갖춘 웹 폼을 구현하는 것을 의미