next server-action

Posted by : on

Category : nextJs   react


서버 액션이란?

브라우저에서 호출할 수 있는 서버에서 실행되는 비동기 함수! 즉 별도의 api를 만들 필요없이, 간단한 함수로 서버 함수를 호출 할 수 있다.

export default function Page() {
    const saveNameAction = async (formData: FormData) => {
        "use server";

        const name = formData.get("name");
        await sql`INSERT INTO Names (name) VALUES (${name})`;
    };

    return (
        <form action={saveNameAction}>
            <input name="name" placeholder="이름을 알려주세요..."/>
            <button type="submit">제출</button>
        </form>
    );
}

위에처럼 form 이벤트가 발생할때 서버에서 실행되는것처럼 저렇게 sql을 보낼수도있고 백엔드의 함수를 실행 할 수도 있다.

백엔드로부터 api 명세를 받게되면 그 api를 호출하는 것들을 작성하면 된다.

//actions/create-contentAction.tsx 와 같이 따로 빼서 하는게 가독성이 좋다.
"use server"

async function saveContentAction(formData: FormData) {
    const content = formData.get('content')?.toString();
    try {
        const response = await fetch(`${process.env.NEXT_PUBLIC_API_SERVER_URL}/review`, {
            method: "POST",
            body: JSON.stringify({content})
        })
    } catch (e) {

    }
}

자동 rerendering하기 revalidatePath

//actions/create-contentAction.tsx 와 같이 따로 빼서 하는게 가독성이 좋다.
"use server"

async function saveContentAction(formData: FormData) {
    const content = formData.get('content')?.toString();
    try {
        const response = await fetch(`${process.env.NEXT_PUBLIC_API_SERVER_URL}/review`, {
            method: "POST",
            body: JSON.stringify({content})
        })
        //1. 특정 주소의 해당하는 페이지만 재검증
        revalidatePath(`/book/${bookId}`)

        //2. 특정 경로의 모든 페이지 재검증
        revalidatePath(`/book/[id]`, "page");

        //3. 특정 레이아웃을 갖는 모든 페이지 재검증 - searchbar 레이아웃을 갖는 모든 페이지를 재검증한다.
        revalidatePath(`/(with-searchbar)`, "layout");

        //4. 모든 데이터 재검증 - 모든 페이지를 재검증
        revalidatePath(`/`, "layout");

        //5. 태그 기준, 데이터 캐시 재검증 아래 소스 참고
        revalidatePath("tag");
    } catch (e) {

    }
}

revalidatePath이걸 호출하게 되면 이 안에 전달된 인수경로에대한 페이지컴포넌트를 다시 검증하여 재렌더링 해준다. 즉 page.tsx에 있는 모든 컴포넌트와 서버액션을 다시 호출한다는 얘기다.

대신 revalidatePath이건 서버단에서만 실행 가능하다. 즉 server컴포넌트에서만 가능하다는 얘기
revalidatePath이게 실행되면 캐싱된 데이터들은 어떻게 하든 다 무표화되기 때문에 fetch같은것들은 다시 생성이 된다.
게다가 풀 라우터 캐시까지 다 초기화 시키고, 다시 업데이트 치진 않는다.. 이건 큰 문제이다. 그래서 새로고침을 다시 해줘야한다.

next-server-action0904.png

이미지와 같이 각종 fetch 데이터들은 다시 set 되지만 풀라우트 캐시는 안되기때문에 재접속시에 풀라우트 캐시를 set 해주게된다. 재접속하게 되었을때 무조건 최신의 데이터를 보장하기위해 이렇게 동작한다고한다.

//actions/create-contentAction.tsx 와 같이 따로 빼서 하는게 가독성이 좋다.
"use server"

async function saveContentAction(formData: FormData) {
    const content = formData.get('content')?.toString();
    try {
        const response = await fetch(`${process.env.NEXT_PUBLIC_API_SERVER_URL}/review`, {
            method: "POST",
            body: JSON.stringify({content})
        })

        //5. 태그 기준, 데이터 캐시 재검증 - 이렇게 태그를 붙여준다음
        revalidatePath(`${bookid}`);
    } catch (e) {

    }
}

// 다른 컴포넌트에서 같은 태그를 next 객체에 넣어주면 revalidatePath이루어질때마다 저 태그를 가진것들이 다시 재검증된다.
async function getList() {
    try {
        const response = await fetch(`${process.env.NEXT_PUBLIC_API_SERVER_URL}/getList`, 
        {next:{tags:[`${bookid}`]}})
    } catch (e) {  

    }
}

이렇게 되면 태그값을 가지고있는 데이터 캐시만 초기화해주기때문에 훨씬 더 경제적으로 할 수 있다.


About 유재석
유재석

개발자 유재석 입니다. Web Developer.

Email : jaeseok9405@gmail.com

Website : https://github.com/yoo94