diff --git a/.claude/agents/docs-reviewer.md b/.claude/agents/docs-reviewer.md
new file mode 100644
index 000000000..af0a856e4
--- /dev/null
+++ b/.claude/agents/docs-reviewer.md
@@ -0,0 +1,28 @@
+---
+name: docs-reviewer
+description: "Lean docs reviewer that dispatches reviews docs for a particular skill."
+model: opus
+color: cyan
+---
+
+You are a direct, critical, expert reviewer for React documentation.
+
+Your role is to use given skills to validate given doc pages for consistency, correctness, and adherence to established patterns.
+
+Complete this process:
+
+## Phase 1: Task Creation
+1. CRITICAL: Read the skill requested.
+2. Understand the skill's requirements.
+3. Create a task list to validate skills requirements.
+
+## Phase 2: Validate
+
+1. Read the docs files given.
+2. Review each file with the task list to verify.
+
+## Phase 3: Respond
+
+You must respond with a checklist of the issues you identified, and line number.
+
+DO NOT respond with passed validations, ONLY respond with the problems.
diff --git a/.claude/settings.json b/.claude/settings.json
new file mode 100644
index 000000000..111403183
--- /dev/null
+++ b/.claude/settings.json
@@ -0,0 +1,32 @@
+{
+ "skills": {
+ "suggest": [
+ {
+ "pattern": "src/content/learn/**/*.md",
+ "skill": "docs-writer-learn"
+ },
+ {
+ "pattern": "src/content/reference/**/*.md",
+ "skill": "docs-writer-reference"
+ }
+ ]
+ },
+ "permissions": {
+ "allow": [
+ "Skill(docs-voice)",
+ "Skill(docs-components)",
+ "Skill(docs-sandpack)",
+ "Skill(docs-rsc-sandpack)",
+ "Skill(docs-writer-learn)",
+ "Skill(docs-writer-reference)",
+ "Bash(yarn lint:*)",
+ "Bash(yarn lint-heading-ids:*)",
+ "Bash(yarn lint:fix:*)",
+ "Bash(yarn tsc:*)",
+ "Bash(yarn check-all:*)",
+ "Bash(yarn fix-headings:*)",
+ "Bash(yarn deadlinks:*)",
+ "Bash(yarn prettier:diff:*)"
+ ]
+ }
+}
diff --git a/.claude/skills/docs-components/SKILL.md b/.claude/skills/docs-components/SKILL.md
new file mode 100644
index 000000000..4b75f27a1
--- /dev/null
+++ b/.claude/skills/docs-components/SKILL.md
@@ -0,0 +1,518 @@
+---
+name: docs-components
+description: Comprehensive MDX component patterns (Note, Pitfall, DeepDive, Recipes, etc.) for all documentation types. Authoritative source for component usage, examples, and heading conventions.
+---
+
+# MDX Component Patterns
+
+## Quick Reference
+
+### Component Decision Tree
+
+| Need | Component |
+|------|-----------|
+| Helpful tip or terminology | `` |
+| Common mistake warning | `` |
+| Advanced technical explanation | `` |
+| Canary-only feature | `` or `` |
+| Server Components only | `` |
+| Deprecated API | `` |
+| Experimental/WIP | `` |
+| Visual diagram | `` |
+| Multiple related examples | `` |
+| Interactive code | `` (see `/docs-sandpack`) |
+| Console error display | `` |
+| End-of-page exercises | `` (Learn pages only) |
+
+### Heading Level Conventions
+
+| Component | Heading Level |
+|-----------|---------------|
+| DeepDive title | `####` (h4) |
+| Titled Pitfall | `#####` (h5) |
+| Titled Note | `####` (h4) |
+| Recipe items | `####` (h4) |
+| Challenge items | `####` (h4) |
+
+### Callout Spacing Rules
+
+Callout components (Note, Pitfall, DeepDive) require a **blank line after the opening tag** before content begins.
+
+**Never place consecutively:**
+- `` followed by `` - Combine into one with titled subsections, or separate with prose
+- `` followed by `` - Combine into one, or separate with prose
+
+**Allowed consecutive patterns:**
+- `` followed by `` - OK for multi-part explorations (see useMemo.md)
+- `` followed by `` - OK when DeepDive explains "why" behind the Pitfall
+
+**Separation content:** Prose paragraphs, code examples (Sandpack), or section headers.
+
+**Why:** Consecutive warnings create a "wall of cautions" that overwhelms readers and causes important warnings to be skimmed.
+
+**Incorrect:**
+```mdx
+
+Don't do X.
+
+
+
+Don't do Y.
+
+```
+
+**Correct - combined:**
+```mdx
+
+
+##### Don't do X {/*pitfall-x*/}
+Explanation.
+
+##### Don't do Y {/*pitfall-y*/}
+Explanation.
+
+
+```
+
+**Correct - separated:**
+```mdx
+
+Don't do X.
+
+
+This leads to another common mistake:
+
+
+Don't do Y.
+
+```
+
+---
+
+## ``
+
+Important clarifications, conventions, or tips. Less severe than Pitfall.
+
+### Simple Note
+
+```mdx
+
+
+The optimization of caching return values is known as [_memoization_](https://en.wikipedia.org/wiki/Memoization).
+
+
+```
+
+### Note with Title
+
+Use `####` (h4) heading with an ID.
+
+```mdx
+
+
+#### There is no directive for Server Components. {/*no-directive*/}
+
+A common misunderstanding is that Server Components are denoted by `"use server"`, but there is no directive for Server Components. The `"use server"` directive is for Server Functions.
+
+
+```
+
+### Version-Specific Note
+
+```mdx
+
+
+Starting in React 19, you can render `` as a provider.
+
+In older versions of React, use ``.
+
+
+```
+
+---
+
+## ``
+
+Common mistakes that cause bugs. Use for errors readers will likely make.
+
+### Simple Pitfall
+
+```mdx
+
+
+We recommend defining components as functions instead of classes. [See how to migrate.](#alternatives)
+
+
+```
+
+### Titled Pitfall
+
+Use `#####` (h5) heading with an ID.
+
+```mdx
+
+
+##### Calling different memoized functions will read from different caches. {/*pitfall-different-caches*/}
+
+To access the same cache, components must call the same memoized function.
+
+
+```
+
+### Pitfall with Wrong/Right Code
+
+```mdx
+
+
+##### `useFormStatus` will not return status information for a `;
+}
+```
+
+Instead call `useFormStatus` from inside a component located inside `
+```
+
+---
+
+## ``
+
+Optional deep technical content. **First child must be `####` heading with ID.**
+
+### Standard DeepDive
+
+```mdx
+
+
+#### Is using an updater always preferred? {/*is-updater-preferred*/}
+
+You might hear a recommendation to always write code like `setAge(a => a + 1)` if the state you're setting is calculated from the previous state. There's no harm in it, but it's also not always necessary.
+
+In most cases, there is no difference between these two approaches. React always makes sure that for intentional user actions, like clicks, the `age` state variable would be updated before the next click.
+
+
+```
+
+### Comparison DeepDive
+
+For comparing related concepts:
+
+```mdx
+
+
+#### When should I use `cache`, `memo`, or `useMemo`? {/*cache-memo-usememo*/}
+
+All mentioned APIs offer memoization but differ in what they memoize, who can access the cache, and when their cache is invalidated.
+
+#### `useMemo` {/*deep-dive-usememo*/}
+
+In general, you should use `useMemo` for caching expensive computations in Client Components across renders.
+
+#### `cache` {/*deep-dive-cache*/}
+
+In general, you should use `cache` in Server Components to memoize work that can be shared across components.
+
+
+```
+
+---
+
+## ``
+
+Multiple related examples showing variations. Each recipe needs ``.
+
+```mdx
+
+
+#### Counter (number) {/*counter-number*/}
+
+In this example, the `count` state variable holds a number.
+
+
+{/* code */}
+
+
+
+
+#### Text field (string) {/*text-field-string*/}
+
+In this example, the `text` state variable holds a string.
+
+
+{/* code */}
+
+
+
+
+
+```
+
+**Common titleText/titleId combinations:**
+- "Basic [hookName] examples" / `examples-basic`
+- "Examples of [concept]" / `examples-[concept]`
+- "The difference between [A] and [B]" / `examples-[topic]`
+
+---
+
+## ``
+
+End-of-page exercises. **Learn pages only.** Each challenge needs problem + solution Sandpack.
+
+```mdx
+
+
+#### Fix the bug {/*fix-the-bug*/}
+
+Problem description...
+
+
+Optional hint text.
+
+
+
+{/* problem code */}
+
+
+
+
+Explanation...
+
+
+{/* solution code */}
+
+
+
+
+
+```
+
+**Guidelines:**
+- Only at end of standard Learn pages
+- No Challenges in chapter intros or tutorials
+- Each challenge has `####` heading with ID
+
+---
+
+## ``
+
+For deprecated APIs. Content should explain what to use instead.
+
+### Page-Level Deprecation
+
+```mdx
+
+
+In React 19, `forwardRef` is no longer necessary. Pass `ref` as a prop instead.
+
+`forwardRef` will be deprecated in a future release. Learn more [here](/blog/2024/04/25/react-19#ref-as-a-prop).
+
+
+```
+
+### Method-Level Deprecation
+
+```mdx
+### `componentWillMount()` {/*componentwillmount*/}
+
+
+
+This API has been renamed from `componentWillMount` to [`UNSAFE_componentWillMount`.](#unsafe_componentwillmount)
+
+Run the [`rename-unsafe-lifecycles` codemod](codemod-link) to automatically update.
+
+
+```
+
+---
+
+## ``
+
+For APIs that only work with React Server Components.
+
+### Basic RSC
+
+```mdx
+
+
+`cache` is only for use with [React Server Components](/reference/rsc/server-components).
+
+
+```
+
+### Extended RSC (for Server Functions)
+
+```mdx
+
+
+Server Functions are for use in [React Server Components](/reference/rsc/server-components).
+
+**Note:** Until September 2024, we referred to all Server Functions as "Server Actions".
+
+
+```
+
+---
+
+## `` and ``
+
+For features only available in Canary releases.
+
+### Canary Wrapper (inline in Intro)
+
+```mdx
+
+
+`` lets you group elements without a wrapper node.
+
+Fragments can also accept refs, enabling interaction with underlying DOM nodes.
+
+
+```
+
+### CanaryBadge in Section Headings
+
+```mdx
+### FragmentInstance {/*fragmentinstance*/}
+```
+
+### CanaryBadge in Props Lists
+
+```mdx
+* **optional** `ref`: A ref object from `useRef` or callback function.
+```
+
+### CanaryBadge in Caveats
+
+```mdx
+* If you want to pass `ref` to a Fragment, you can't use the `<>...>` syntax.
+```
+
+---
+
+## ``
+
+Visual explanations of module dependencies, render trees, or data flow.
+
+```mdx
+
+`'use client'` segments the module dependency tree, marking `InspirationGenerator.js` and all dependencies as client-rendered.
+
+```
+
+**Attributes:**
+- `name`: Diagram identifier (used for image file)
+- `height`: Height in pixels
+- `width`: Width in pixels
+- `alt`: Accessible description of the diagram
+
+---
+
+## `` (Use Sparingly)
+
+Numbered callouts in prose. Pairs with code block annotations.
+
+### Syntax
+
+In code blocks:
+```mdx
+```js [[1, 4, "age"], [2, 4, "setAge"], [3, 4, "42"]]
+import { useState } from 'react';
+
+function MyComponent() {
+ const [age, setAge] = useState(42);
+}
+```
+```
+
+Format: `[[step_number, line_number, "text_to_highlight"], ...]`
+
+In prose:
+```mdx
+1. The current state initially set to the initial value.
+2. The `set` function that lets you change it.
+```
+
+### Guidelines
+
+- Maximum 2-3 different colors per explanation
+- Don't highlight every keyword - only key concepts
+- Use for terms in prose, not entire code blocks
+- Maintain consistent usage within a section
+
+✅ **Good use** - highlighting key concepts:
+```mdx
+React will compare the dependencies with the dependencies you passed...
+```
+
+🚫 **Avoid** - excessive highlighting:
+```mdx
+When an Activity boundary is hidden during its initial render...
+```
+
+---
+
+## ``
+
+Display console output (errors, warnings, logs).
+
+```mdx
+
+Uncaught Error: Too many re-renders.
+
+```
+
+**Levels:** `error`, `warning`, `info`
+
+---
+
+## Component Usage by Page Type
+
+### Reference Pages
+
+For component placement rules specific to Reference pages, invoke `/docs-writer-reference`.
+
+Key placement patterns:
+- `` goes before `` at top of page
+- `` goes after `` for page-level deprecation
+- `` goes after method heading for method-level deprecation
+- `` wrapper goes inline within ``
+- `` appears in headings, props lists, and caveats
+
+### Learn Pages
+
+For Learn page structure and patterns, invoke `/docs-writer-learn`.
+
+Key usage patterns:
+- Challenges only at end of standard Learn pages
+- No Challenges in chapter intros or tutorials
+- DeepDive for optional advanced content
+- CodeStep should be used sparingly
+
+### Blog Pages
+
+For Blog page structure and patterns, invoke `/docs-writer-blog`.
+
+Key usage patterns:
+- Generally avoid deep technical components
+- Note and Pitfall OK for clarifications
+- Prefer inline explanations over DeepDive
+
+---
+
+## Other Available Components
+
+**Version/Status:** ``, ``, ``, ``, ``
+
+**Visuals:** ``, ``, ``, ``, ``
+
+**Console:** ``, ``
+
+**Specialized:** ``, ``, ``, ``, ``, ``, `
+
+
+ {message}
+
+
);
}
diff --git a/src/components/PageHeading.tsx b/src/components/PageHeading.tsx
index ee92f5e55..3cfb6337d 100644
--- a/src/components/PageHeading.tsx
+++ b/src/components/PageHeading.tsx
@@ -14,8 +14,12 @@ import Tag from 'components/Tag';
import {H1} from './MDX/Heading';
import type {RouteTag, RouteItem} from './Layout/getRouteMeta';
import * as React from 'react';
+import {useState, useEffect} from 'react';
+import {useRouter} from 'next/router';
import {IconCanary} from './Icon/IconCanary';
import {IconExperimental} from './Icon/IconExperimental';
+import {IconCopy} from './Icon/IconCopy';
+import {Button} from './Button';
interface PageHeadingProps {
title: string;
@@ -27,6 +31,51 @@ interface PageHeadingProps {
breadcrumbs: RouteItem[];
}
+function CopyAsMarkdownButton() {
+ const {asPath} = useRouter();
+ const [copied, setCopied] = useState(false);
+
+ useEffect(() => {
+ if (!copied) return;
+ const timer = setTimeout(() => setCopied(false), 2000);
+ return () => clearTimeout(timer);
+ }, [copied]);
+
+ async function fetchPageBlob() {
+ const cleanPath = asPath.split(/[?#]/)[0];
+ const res = await fetch(cleanPath + '.md');
+ if (!res.ok) throw new Error('Failed to fetch');
+ const text = await res.text();
+ return new Blob([text], {type: 'text/plain'});
+ }
+
+ async function handleCopy() {
+ try {
+ await navigator.clipboard.write([
+ // Don't wait for the blob, or Safari will refuse clipboard access
+ new ClipboardItem({'text/plain': fetchPageBlob()}),
+ ]);
+ setCopied(true);
+ } catch {
+ // Silently fail
+ }
+ }
+
+ return (
+
+ );
+}
+
function PageHeading({
title,
status,
@@ -37,7 +86,12 @@ function PageHeading({
return (
- {breadcrumbs ? : null}
+
+
+ {breadcrumbs ? : null}
+
+
+
{title}
{version === 'canary' && (
diff --git a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md
index dcc29aab1..0cc8e0ef1 100644
--- a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md
+++ b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md
@@ -31,7 +31,7 @@ RSC는 서버 중심의 멀티 페이지 애플리케이션의 간단한 "요청
이제 데이터 가져오기Fetching가 어느 정도 잘 정리되었으므로 다른 방향을 살펴보고 있습니다. 바로 클라이언트에서 서버로 데이터를 전송하여 데이터베이스 변경을 실행하고 폼을 구현할 수 있도록 하는 것입니다. 서버와 클라이언트의 경계를 넘어 서버 액션 함수를 전달하면 클라이언트가 이를 호출하여 원활한 RPC를 제공할 수 있습니다. 서버 액션은 또한 자바스크립트를 불러오기 전에 점진적으로 향상된 폼을 제공합니다.
-React 서버 컴포넌트는 [Next.js App 라우터](/learn/start-a-new-react-project#nextjs-app-router)에 포함되어 있습니다. Next.js에서는 라우터와 깊은 결합을 통해 RSC를 기본 요소로 받아들이는 것을 보여줍니다. 그러나 이 방법이 RSC와 호환할 수 있는 라우터나 프레임워크를 구축하는 유일한 방법은 아닙니다. RSC 명세와 구현에서 제공하는 기능에는 명확한 구분이 있습니다. React 서버 컴포넌트는 호환할 수 있는 React 프레임워크에서 동작하는 컴포넌트에 대한 명세입니다.
+React 서버 컴포넌트는 [Next.js App 라우터](/learn/creating-a-react-app#nextjs-app-router)에 포함되어 있습니다. Next.js에서는 라우터와 깊은 결합을 통해 RSC를 기본 요소로 받아들이는 것을 보여줍니다. 그러나 이 방법이 RSC와 호환할 수 있는 라우터나 프레임워크를 구축하는 유일한 방법은 아닙니다. RSC 명세와 구현에서 제공하는 기능에는 명확한 구분이 있습니다. React 서버 컴포넌트는 호환할 수 있는 React 프레임워크에서 동작하는 컴포넌트에 대한 명세입니다.
우리는 일반적으로 기존 프레임워크를 권장하지만, 직접 사용자 지정 프레임워크를 구축해야 하는 경우도 가능합니다. RSC와 호환할 수 있는 프레임워크를 직접 구축하는 것은 번들러와의 깊은 결합을 필요로하기 때문에 생각만큼 쉽지 않습니다. 현재 세대의 번들러는 클라이언트에서 사용하기에는 훌륭하지만, 서버와 클라이언트 간에 단일 모듈 그래프를 분할하는 것을 우선으로 지원하도록 설계되지 않았습니다. 이것이 지금 RSC를 내장하기 위한 기본 요소를 얻기 위해 번들러 개발자들과 직접 협력하는 이유입니다.
@@ -92,7 +92,7 @@ React 컴포넌트의 순수한 자바스크립트를 반응형으로 만들기
## 트랜지션 추적 {/*transition-tracing*/}
-트랜지션 추적 API를 통해 [React 트랜지션](/reference/react/useTransition)이 느려지는 시점을 감지하고 느려지는 이유를 조사할 수 있습니다. 지난 업데이트 이후 API의 초기 설계를 마무리하고 [RFC](https://github.com/reactjs/rfcs/pull/238)를 공개했습니다. 기본 기능도 함께 구현되었습니다. 이 프로젝트는 현재 보류 중입니다. RFC에 대한 피드백을 환영하며, 개발을 재개하여 React를 위한 더 나은 성능 측정 도구를 제공할 수 있기를 기대합니다. 이는 [Next.js App 라우터](/learn/start-a-new-react-project#nextjs-app-router)와 같이 React 트랜지션 위에 구축된 라우터에서는 특히 더 유용할 것입니다.
+트랜지션 추적 API를 통해 [React 트랜지션](/reference/react/useTransition)이 느려지는 시점을 감지하고 느려지는 이유를 조사할 수 있습니다. 지난 업데이트 이후 API의 초기 설계를 마무리하고 [RFC](https://github.com/reactjs/rfcs/pull/238)를 공개했습니다. 기본 기능도 함께 구현되었습니다. 이 프로젝트는 현재 보류 중입니다. RFC에 대한 피드백을 환영하며, 개발을 재개하여 React를 위한 더 나은 성능 측정 도구를 제공할 수 있기를 기대합니다. 이는 [Next.js App 라우터](/learn/creating-a-react-app#nextjs-app-router)와 같이 React 트랜지션 위에 구축된 라우터에서는 특히 더 유용할 것입니다.
* * *
이번 업데이트 외에도 최근 우리 팀은 커뮤니티 팟캐스트와 라이브스트림에 초청자로 출연하여 우리의 작업에 대해 더 많은 이야기를 나누고 질문에 답변했습니다.
diff --git a/src/content/blog/2024/05/22/react-conf-2024-recap.md b/src/content/blog/2024/05/22/react-conf-2024-recap.md
index 39662d070..5a1efa194 100644
--- a/src/content/blog/2024/05/22/react-conf-2024-recap.md
+++ b/src/content/blog/2024/05/22/react-conf-2024-recap.md
@@ -43,14 +43,14 @@ _[1일 차 전체 스트리밍 시청하기.](https://www.youtube.com/watch?v=T8
- [Josh Story](https://twitter.com/joshcstory): [React 19 심층 탐구: HTML 조정](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=24916s)
- [Aurora Walberg Scharff](https://twitter.com/aurorascharff): [React 서버 컴포넌트로 폼 향상](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=25280s)
- [Dan Abramov](https://bsky.app/profile/danabra.mov): [두 대의 컴퓨터용 React](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=18825s)
-- [Kent C. Dodds](https://twitter.com/kentcdodds): [이제 React 서버 컴포넌트를 이해합니다](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=11256s)
+- [Kent C. Dodds](https://twitter.com/kentcdodds): [이제 React 서버 컴포넌트를 이해합니다](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=11256s)
마지막으로 [Joe Savona](https://twitter.com/en_JS), [Sathya Gunasekaran](https://twitter.com/_gsathya), [Mofei Zhang](https://twitter.com/zmofei)은 React 컴파일러가 [오픈소스](https://github.com/facebook/react/pull/29061)로 공개되었음을 알리고, 실험 버전을 공유했습니다.
컴파일러 사용법과 동작 방식은 [관련 문서](/learn/react-compiler) 및 관련 강연을 확인하세요.
- [Lauren Tan](https://twitter.com/potetotes): [Memo를 신경 쓰지 마세요](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=12020s)
-- [Sathya Gunasekaran](https://twitter.com/_gsathya) & [Mofei Zhang](https://twitter.com/zmofei): [React 컴파일러 심층 탐구](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=9313s)
+- [Sathya Gunasekaran](https://twitter.com/_gsathya) & [Mofei Zhang](https://twitter.com/zmofei): [React 컴파일러 심층 탐구](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=9313s)
1일 차 기조연설 전체 시청하기
@@ -85,7 +85,7 @@ _[2일 차 전체 스트리밍 시청하기](https://www.youtube.com/watch?v=0ck
React와 React Native 팀은 매일 Q&A 세션으로 하루를 마무리했습니다.
-- [Michael Chan](https://twitter.com/chantastic)이 진행한 [React Q&A](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=27518s)
+- [Michael Chan](https://twitter.com/chantastic)이 진행한 [React Q&A](https://www.youtube.com/watch?v=T8TZQ6k4SLE&t=27518s)
- [Jamon Holmgren](https://twitter.com/jamonholmgren)이 진행한 [React Native Q&A](https://www.youtube.com/watch?v=0ckOUBiuxVY&t=27935s)
## 그리고... {/*and-more*/}
diff --git a/src/content/blog/2024/12/05/react-19.md b/src/content/blog/2024/12/05/react-19.md
index e60c6f735..951e33d76 100644
--- a/src/content/blog/2024/12/05/react-19.md
+++ b/src/content/blog/2024/12/05/react-19.md
@@ -117,7 +117,7 @@ function UpdateName({}) {
액션은 데이터 제출을 자동으로 관리합니다.
-- **대기 상태**: 액션은 요청 시작 시 대기 상태를 활성화하고 최종 상태가 커밋되었을때 자동으로 초기화합니다.
+- **대기 상태**: 액션은 요청 시작 시 대기 상태를 활성화하고 최종 상태가 커밋되었을 때 자동으로 초기화합니다.
- **낙관적 업데이트**: 액션은 새로운 [`useOptimistic`](#new-hook-optimistic-updates)훅을 통해 사용자가 요청을 제출하는 동안 즉각적인 피드백을 표시할 수 있습니다.
- **에러 처리**: 액션은 요청 실패 시 Error Boundary를 보여주고 낙관적 업데이트를 원래 값으로, 자동으로 돌려놓습니다.
- **폼**: `