'use server'
'use server'
๋ฅผ ์ฌ์ฉํ์ฌ ํด๋ผ์ด์ธํธ ์ธก ์ฝ๋์์ ํธ์ถํ ์ ์๋ ์๋ฒ ์ธก ํจ์๋ฅผ ํ์ํฉ๋๋ค.
๋ ํผ๋ฐ์ค
'use server'
ํจ์๋ฅผ ํด๋ผ์ด์ธํธ์์ ํธ์ถํ ์ ์์์ ํ์ํ๊ธฐ ์ํด, ๋น๋๊ธฐ ํจ์์ ์ต์๋จ์ 'use server';
๋ฅผ ์ถ๊ฐํ์ธ์. ์ด๋ฅผ ์๋ฒ ํจ์๋ผ๊ณ ๋ถ๋ฆ
๋๋ค.
async function addToCart(data) {
'use server';
// ...
}
ํด๋ผ์ด์ธํธ์์ ์๋ฒ ํจ์๋ฅผ ํธ์ถํ๋ฉด, ์ ๋ฌ๋ ๋ชจ๋ ์ธ์์ ์ง๋ ฌํ๋ ์ฌ๋ณธ์ ํฌํจํ ๋คํธ์ํฌ ์์ฒญ์ ์๋ฒ๋ก ์ ์กํฉ๋๋ค. ์๋ฒ ํจ์๊ฐ ๊ฐ์ ๋ฐํํ๋ฉด, ๊ทธ ๊ฐ์ ์ง๋ ฌํํ์ฌ ํด๋ผ์ด์ธํธ๋ก ๋ฐํํฉ๋๋ค.
ํจ์ ๊ฐ๊ฐ์ 'use server'
๋ฅผ ํ๊ธฐํ๋ ๋์ , ํ์ผ์ ์ต์๋จ์ ์ง์์ด๋ฅผ ์ถ๊ฐํ์ฌ ํ์ผ์ ๋ชจ๋ ๋ด๋ณด๋ด๊ธฐExport๋ฅผ ํด๋ผ์ด์ธํธ๋ฅผ ํฌํจํ ๋ชจ๋ ๊ณณ์์ ์ฌ์ฉํ ์ ์๋ ์๋ฒ ํจ์๋ก ํ๊ธฐํ ์ ์์ต๋๋ค.
์ฃผ์ ์ฌํญ
'use server'
๋ ํจ์ ๋๋ ๋ชจ๋์ ์ต์๋จ์ ์์ด์ผ ํฉ๋๋ค.import
๋ฅผ ํฌํจํ ๋ค๋ฅธ ์ฝ๋๋ณด๋ค ์์ ์์ด์ผ ํฉ๋๋ค. (์ง์์ด ์์ ์ฃผ์์ ๊ด์ฐฎ์ต๋๋ค.) ๋ฐฑํฑ์ด ์๋ ๋จ์ผ ๋๋ ์ด์ค ๋ฐ์ดํ๋ก ์์ฑํด์ผ ํฉ๋๋ค.'use server'
๋ ์๋ฒ ์ธก ํ์ผ์์๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์์ฑ๋ ์๋ฒ ํจ์๋ Props๋ฅผ ํตํด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์ ๋ฌํ ์ ์์ต๋๋ค. ์ง์๋๋ ์ง๋ ฌํ ํ์ ์ ์ฐธ๊ณ ํ์ธ์.- ์๋ฒ ํจ์๋ฅผ ํด๋ผ์ด์ธํธ ์ฝ๋์์ ๊ฐ์ ธ์ค๊ธฐImport ์ํด, ์ง์์ด๋ฅผ ๋ชจ๋ ์์ค์์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
- ๊ธฐ๋ณธ ๋คํธ์ํฌ ํธ์ถ์ด ํญ์ ๋น๋๊ธฐ์ ์ด๋ฏ๋ก,
'use server'
๋ ๋น๋๊ธฐ ํจ์์์๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค. - ํญ์ ์๋ฒ ํจ์์ ์ธ์๋ฅผ ์ ๋ขฐํ ์ ์๋ ์ ๋ ฅ์ผ๋ก ์ทจ๊ธํ๊ณ ๋ชจ๋ ๋ณ๊ฒฝ์ ๊ฒํ ํ์ธ์. ๋ณด์ ๊ณ ๋ ค์ฌํญ์ ํ์ธํ์ธ์.
- ์๋ฒ ํจ์๋ Transition ์์์ ํธ์ถ๋์ด์ผ ํฉ๋๋ค.
<form action>
๋๋formAction
์ผ๋ก ์ ๋ฌ๋ ์๋ฒ ํจ์๋ ์๋์ผ๋ก Transition ๋ด์์ ํธ์ถ๋ฉ๋๋ค. - ์๋ฒ ํจ์๋ ์๋ฒ ์ธก ์ํ๋ฅผ ์ ๋ฐ์ดํธํ๋ Mutation์ ์ํด ์ค๊ณ๋์์ผ๋ฉฐ, ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐFetching์๋ ๊ถ์ฅํ์ง ์์ต๋๋ค. ๋ฐ๋ผ์, ์๋ฒ ํจ์๋ฅผ ๊ตฌํํ๋ ํ๋ ์์ํฌ๋ ์ผ๋ฐ์ ์ผ๋ก ํ ๋ฒ์ ํ๋์ ์์ ๋ง ์ฒ๋ฆฌํ๋ฉฐ, ๋ฐํ ๊ฐ์ ์บ์ํ๋ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ง ์์ต๋๋ค.
๋ณด์ ๊ณ ๋ ค์ฌํญ
์๋ฒ ํจ์์ ๋ํ ์ธ์๋ ํด๋ผ์ด์ธํธ์์ ์์ ํ ์ ์ด๋ฉ๋๋ค. ๋ณด์์ ์ํด ํญ์ ์ ๋ขฐํ ์ ์๋ ์ ๋ ฅ์ผ๋ก ์ทจ๊ธํ์ฌ, ์ธ์๋ฅผ ์ ์ ํ๊ฒ ๊ฒ์ฆํ๊ณ ์ด์ค์ผ์ดํ ํ๋์ง ํ์ธํ์ธ์.
๋ชจ๋ ์๋ฒ ํจ์์์ ๋ก๊ทธ์ธํ ์ฌ์ฉ์๊ฐ ํด๋น ์์ ์ ์ํํ ์ ์๋์ง ํ์ธํ์ธ์.
์ง๋ ฌํ ๊ฐ๋ฅ ์ธ์์ ๋ฐํ๊ฐ
ํด๋ผ์ด์ธํธ ์ฝ๋๊ฐ ๋คํธ์ํฌ๋ฅผ ํตํด ์๋ฒ ํจ์๋ฅผ ํธ์ถํ๋ฏ๋ก, ์ ๋ฌํ๋ ๋ชจ๋ ์ธ์๋ ์ง๋ ฌํ ๊ฐ๋ฅํด์ผ ํฉ๋๋ค.
๋ค์์ ์๋ฒ ํจ์์ ์ธ์๋ก ์ง์๋๋ ํ์ ์ ๋๋ค.
- ์์ ์๋ฃํ
- ์ง๋ ฌํํ ์ ์๋ ๊ฐ์ ํฌํจํ๋ ์ดํฐ๋ฌ๋ธ
- Date
- FormData ์ธ์คํด์ค
- ์ผ๋ฐ ๊ฐ์ฒด (์ง๋ ฌํํ ์ ์๋ ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฒด ์ด๋์ ๋ผ์ด์ ๋ก ์์ฑ๋ ๊ฐ์ฒด)
- ์๋ฒ ํจ์๋ก์์ ํจ์
- Promise
๋จ, ๋ค์์ ์ง์๋์ง ์์ต๋๋ค.
- React ์๋ฆฌ๋จผํธ ๋๋ JSX
- ์ปดํฌ๋ํธ ํจ์ ๋๋ ์๋ฒ ํจ์๊ฐ ์๋ ๋ค๋ฅธ ํจ์๋ฅผ ํฌํจํ๋ ํจ์
- ํด๋์ค
- ํด๋์ค์ ์ธ์คํด์ค์ธ ๊ฐ์ฒด(์ธ๊ธ๋ ๋ด์ฅ ๊ฐ์ฒด ์ ์ธ)๋๋ null ํ๋กํ ํ์ ์ด ์๋ ๊ฐ์ฒด
- ์ ์ญ์ ๋ฑ๋ก๋์ง ์์ Symbol (์:
Symbol('my new symbol')
) - Events from event handlers
์ง์๋๋ ์ง๋ ฌํ ๊ฐ๋ฅํ ๋ฐํ ๊ฐ์ ๊ฒฝ๊ณ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์ ์ง๋ ฌํ ๊ฐ๋ฅํ Props์ ๋์ผํฉ๋๋ค.
์ฌ์ฉ๋ฒ
Server Functions in forms
์๋ฒ ํจ์์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก๋, ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ๋ ์๋ฒ ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ์ ๋๋ค. ๋ธ๋ผ์ฐ์ ์ HTML ํผ ์๋ฆฌ๋จผํธ๋ ์ฌ์ฉ์๊ฐ Mutation์ ์ ์ถํ๋ ์ ํต์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค. React ์๋ฒ ์ปดํฌ๋ํธ๋ฅผ ํตํด, React๋ ํผForm์์ ์ก์ ์ผ๋ก ์ฌ์ฉ๋๋ ์๋ฒ ํจ์์ ๋ํ ์ต์์ ์ง์์ ์ ๊ณตํฉ๋๋ค.
์ฌ๊ธฐ, ์ฌ์ฉ์๊ฐ ์ฌ์ฉ์ ์ด๋ฆ์ ์์ฒญํ ์ ์๋ ํผForm์ด ์์ต๋๋ค.
// 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>
์ ํตํ ์๋ฒ ํจ์์
๋๋ค. ์ฌ์ฉ์๊ฐ ์ด ํผForm์ ์ ์ถํ๋ฉด ์๋ฒ ํจ์์ธ requestUsername
์ ๋คํธ์ํฌ ์์ฒญ์ ๋ณด๋
๋๋ค. ํผForm์์ ์๋ฒ ํจ์๋ฅผ ํธ์ถํ ๋, React๋ ํผForm์ formData๋ฅผ ์๋ฒ ํจ์์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ ๊ณตํฉ๋๋ค.
์๋ฒ ํจ์๋ฅผ ํผ action
์ ์ ๋ฌํ์ฌ, React๋ ํผ์ ์ ์ง์ ํฅ์ํ ์ ์์ต๋๋ค. ์ด๊ฒ์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฒ๋ค์ ๋ก๋ํ๊ธฐ ์ ์ ์์์ ์ ์ถํ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
ํผ์์ ๋ฐํ ๊ฐ ์ฒ๋ฆฌ
In the username request form, there might be the chance that a username is not available. requestUsername
should tell us if it fails or not.
์ ์ง์ ํฅ์์ ์ง์ํ๋ฉฐ ์๋ฒ ํจ์์ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก 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
๋ ํด๋ผ์ด์ธํธ ์ฝ๋์์๋ง ํธ์ถํ ์ ์์ต๋๋ค.
<form>
์ธ๋ถ์์ ์๋ฒ ํจ์ ํธ์ถํ๊ธฐ
์๋ฒ ํจ์๋ ๋ ธ์ถ๋ ์๋ฒ ์๋ํฌ์ธํธ์ด๋ฉฐ ํด๋ผ์ด์ธํธ ์ฝ๋ ์ด๋์์๋ ํธ์ถํ ์ ์์ต๋๋ค.
ํผForm ์ธ๋ถ์์ ์๋ฒ ํจ์๋ฅผ ์ฌ์ฉํ ๋, Transition์์ ์๋ฒ ํจ์๋ฅผ ํธ์ถํ๋ฉด ๋ก๋ฉ ์ธ๋์ผ์ดํฐLoading Indicator๋ฅผ ํ์ํ๊ณ , ๋๊ด์ ์ํ ์ ๋ฐ์ดํธ๋ฅผ ํ์ํ๋ฉฐ ์๊ธฐ์น ์์ ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. ํผ์ Transition์ ์๋ฒ ํจ์๋ฅผ ์๋์ผ๋ก ๋ํํฉ๋๋ค.
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;
}
์๋ฒ ํจ์์ ๋ฐํ ๊ฐ์ ์ฝ์ผ๋ ค๋ฉด ๋ฐํ๋ Promise๋ฅผ await
ํด์ผํฉ๋๋ค.