Server Actions

데이터 변이 - 심층분석

  • react 에서 제공함 (넥스트 한정 X)
  • form 의 action 속성은 server action을 지정함
const NewPostPage = () => {
  const submitPostHandler = async (postData) => {
    "use server" // <---------- 이게 핵심
    ...
    console.log(data); // <---------- 터미널에 출력
  };

  return (
    ...
  )
};

useFormStatus

  • react 제공
  • <form> tag 중간에 사용
  • client 컴포넌트에서 사용
"use client"
import { useFormStatus } from 'react';

export default function NewPostPage() {
  const { pending, data, method, action } = useFormStatus();

  return (
    ...
  )
}

useActionState

  • react 제공
  • 원래 useFormState 였으나, useActionState로 변경됨
  • client 컴포넌트에서 사용
"use client"
import { useActionState } from 'react';

export default function NewPostPage() {

  // 에러 발생 (server action in client component)
  const createPost = async (postData) => {
    "use server"
    ...
  };

  const [state, formAction] = useActionState(createPost, initialState, permalink?);

  return (
    <>
      <form action={formAction}>
        ...
      </form>
    </>
  )
}
  • 해결방법: client 컴포넌트를 분리하기
  • 해결방법2: server action을 분리하기

“use server”

  • 지시만 할 뿐,

    ⚠️ 서버에서만 실행된다는 것을 의미하거나 보장하지 않음

    • 클라에서 숨기기 위해 사용 부적합
  • server action이든 아니든 클라쪽에서 절대 실행하면 안되는 코드 있다면 server-only 패키지를 사용해야 함

revalidation

  • revalidate() (from next/cache) 사용
  • ex: revalidate('/posts/[id]', 'layout')

useOptimistic

  • 서버 액션 안기다려도 됨!

  • 첫번째 인자: 초기 데이터
  • 두번째 인자: 콟백 함수
export const Posts = () => {
  //
  const [opmitisticPosts, updateOptmisticPosts] = useOptimistic(posts, (prevPosts, updatedPostId) => {
    return prevPosts.map((post) => {
      if (post.id === updatedPostId) {
        return { ...post, likes: post.likes + 1 };
      }
      return post;
    });
  });

  const likePostHandler = async (postId) => {
    // optimistic update
    updateOptmisticPosts(postId);
    // server update
    await fetch(`/api/posts/${postId}/like`, { method: 'POST' });
  };
};

Caching (dev vs prod)

npm run build 
  • production mode에서는 꽤 공격적인 캐싱이 되어 있어 의도된 대로 동작하지 않을 수 있음
  • revalidate() 사용하여 캐싱을 무효화할 수 있음