'use server'
는 클라이언트 측 코드에서 호출할 수 있는 서버 측 함수를 표시합니다.
레퍼런스
'use server'
함수가 클라이언트에서 실행될 수 있음을 표시하기 위해, 비동기 함수의 맨 위에 'use server';
를 추가하세요. 우리는 이를 Server Actions 이라고 부릅니다.
async function addToCart(data) {
'use server';
// ...
}
Server Action을 클라이언트에서 호출하면, 직렬화된 인자의 사본을 포함하는 서버로의 네트워크 요청이 생성됩니다. Server Action이 값을 반환하면, 그 값은 직렬화되고 클라이언트에 반환됩니다.
함수 각각에 'use server'
를 표기하는 대신, 파일의 맨 위에 지시어를 추가하여 파일의 모든 export를, 클라이언트를 포함한 모든 곳에서 사용할 수 있는 Server Action으로 표기할 수 있습니다.
주의사항
'use server'
는 함수 또는 모듈의 맨 처음에 있어야 합니다. import를 포함한 다른 코드보다 위에 있어야 합니다.(지시어 위의 주석은 괜찮습니다). 백틱이 아닌 단일 또는 이중 따옴표로 작성해야 합니다.'use server'
는 서버 측 파일에서만 사용할 수 있습니다. 결과적인 Server Action은 props를 통해 클라이언트 컴포넌트로 전달할 수 있습니다. 제공되는 직렬화 타입을 참고하세요.- Server Action을 클라이언트 코드에서 import 하기 위해, 지시어는 모듈 수준에서 사용되어야 합니다.
- 기본 네트워크 호출이 항상 비동기이므로
'use server'
는 비동기 함수에서만 사용할 수 있습니다. - 항상 Server Action의 인자를 신뢰할 수 없는 입력으로 취급하고 모든 변경을 검토하세요. 보안 고려사항을 확인하세요.
- Server Action은 transition 안에서 호출되어야합니다.
<form action>
또는formAction
로 전달된 Server Action은 자동으로 transition 내에서 호출됩니다. - Server Action은 서버 측 상태를 업데이트하는 mutation을 위해 설계되었으며 데이터 fetching에는 권장되지 않습니다. 따라서 서버 액션을 구현하는 프레임워크는 일반적으로 한 번에 하나의 액션을 처리하며 반환 값을 캐시할 방법이 없습니다.
보안 고려사항
Server Action에 대한 인수는 완전히 클라이언트에서 제어됩니다. 보안을 위해 항상 신뢰할 수 없는 입력으로 취급하여, 인자를 적절하게 검증하고 이스케이프 하는지 확인하세요.
Server Action에서 로그인한 사용자가 해당 작업을 수행할 수 있는지 확인하세요.
직렬화 가능 인수와 반환값
클라이언트 코드가 네트워크를 통해 서버 작업을 호출할 때 전달된 인수는 모두 직렬화되어야 합니다.
다음은 지원되는 Server Action 인자의 타입입니다.
- Primitives
- 직렬화 가능한 값을 포함한 Iterables
- Date
- FormData 인스턴스
- object initializers로 직렬화 가능한 속성과 함께 생성된 일반 objects
- Server Action인 함수
- Promises
특히 다음은 지원되지 않습니다.
- React 엘리먼트 또는 JSX
- 컴포넌트 함수 또는 Server Action이 아닌 다른 함수를 포함하는 함수
- 클래스
- 클래스의 인스턴스인 객체(언급된 내장 객체 제외)또는 null 프로토타입이 있는 개체
- 전역에 등록되지 않은 Symbol, 예.
Symbol('my new symbol')
지원되는 직렬화 가능한 반환 값은 경계 클라이언트 컴포넌트의 직렬화 가능한 props와 동일합니다.
Server Action 형식
Server Action의 가장 일반적인 사용 사례는, 데이터를 변경하는 서버 함수를 호출하는 것입니다. 브라우저에서 HTML 폼 엘리먼트는 사용자가 mutation을 제출하는 전통적인 접근 방식입니다. React 서버 컴포넌트로, React는 forms에서 Server Action에 대한 최상의 지원을 제공합니다.
사용자가 사용자 이름을 요청할 수 있는 양식이 있습니다.
// App.js
async function requestUsername(formData) {
'use server';
const username = formData.get('username');
// ...
}
export default function App() {
return (
<form action={requestUsername}>
<input type="text" name="username" />
<button type="submit">Request</button>
</form>
);
}
예시에서 requestUsername
는 <form>
을 통한 Server Action입니다. 사용자가 이 양식을 제출하면 서버 함수인 requestUsername
에 네트워크 요청이 있습니다. 폼에서 Server Action을 호출할 때 React는 폼의 FormData를 Server Action의 첫 번째 인자로 제공합니다.
Server Action을 폼 action
에 전달하여, React는 폼을 점진적 향상할 수 있습니다. 이것은 자바스크립트 번들이 로드되기 전에 양식을 제출할 수 있다는 것을 의미합니다.
폼에서 반환 값 처리
점진적 향상을 지원하며 Server Action의 결과를 기반으로 UI를 업데이트하려면, useActionState
를 사용하세요.
// requestUsername.js
'use server';
export default async function requestUsername(formData) {
const username = formData.get('username');
if (canRequest(username)) {
// ...
return 'successful';
}
return 'failed';
}
// UsernameForm.js
'use client';
import { useActionState } from 'react';
import requestUsername from './requestUsername';
function UsernameForm() {
const [state, action] = useActionState(requestUsername, null, 'n/a');
return (
<>
<form action={action}>
<input type="text" name="username" />
<button type="submit">Request</button>
</form>
<p>Last submission request returned: {state}</p>
</>
);
}
대부분의 Hook과 마찬가지로 useActionState
는 client code에서만 호출할 수 있습니다.
<form>
외부에서 Server Action 호출하기
Server Action은 노출된 서버 엔드포인트이며 클라이언트 코드 어디에서나 호출할 수 있습니다.
form 외부에서 Server Action을 사용할 때, Transition에서 서버 액션을 호출하면 로딩 인디케이터를 표시하고, 낙관적 상태 업데이트를 표시하며 예기치 않은 오류를 처리할 수 있습니다. 폼은 transition의 Server Action을 자동으로 래핑합니다.
import incrementLike from './actions';
import { useState, useTransition } from 'react';
function LikeButton() {
const [isPending, startTransition] = useTransition();
const [likeCount, setLikeCount] = useState(0);
const onClick = () => {
startTransition(async () => {
const currentCount = await incrementLike();
setLikeCount(currentCount);
});
};
return (
<>
<p>Total Likes: {likeCount}</p>
<button onClick={onClick} disabled={isPending}>Like</button>;
</>
);
}
// actions.js
'use server';
let likeCount = 0;
export default async function incrementLike() {
likeCount++;
return likeCount;
}
Server Action 반환 값을 읽으려면 반환된 promise를 await
해야합니다.