next.js server action

완두콩·2023년 9월 12일
0

Next.js

목록 보기
14/16

next13.4에서 server action이라는 실험적 기능이 생겼다.
사실 13버전 이전의 버전은 사용해본 적이 없기 때문에 어디가 더 나아진 건지 알지 못한다. 그냥 배울 뿐...ㅋ

server action에 관한 내용이 많지 않아 100% 이해하진 못했다.
한국어로 된 설명도 아직도 뭐가 뭔지 모르겠다.
영어로 된 유튜브 설명을 듣고 번역하고 해서 대충 알아듣는 정도...
써보면서 이해한다.

사용 이유

DB에 데이터를 저장하고 싶으면 서버를 거치는데
그러기 위해 서버 파일을 만들어 API를 작성하고 뭐하고 번거로울 때
page.js안에서 해결할 수 있음.

코드 예시 -product warehouse

next.config.js 파일을 열어서 아래 코드 넣어줌.

const nextConfig = {
   // 서버액션
   experimental: {
       serverActions: true,
   }
}

page.js에서 async로 페이지를 만든다.

그리고 서버로 전송할 데이터를 입력할 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' 적어줌
  2. form action 에 함수이름 넣기
  3. input에 이름 주기(함수에서 이름으로 불러올 수 있게)
  4. 인풋의 내용을 문자열로 가져오기. 없으면 리턴한다.
  5. 추가할 입력 값을 newProduct로 만들어준다.
  6. api로 POST하기 - 이렇게 하면 따로 api라우트를 만들어서 하지 않아도 됨!
//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')

  }
  
  

server action의 장점

"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 등을 사용하여 더 많은 기능을 추가할 수 있도록 하는 웹 접근성과 호환성을 갖춘 웹 폼을 구현하는 것을 의미

profile
공부하자. 기록하자. 쫌!

0개의 댓글