asChild={true}일 때:
asChild={false} 또는 생략할 때:
// asChild={true} - Button이 실제 DOM 요소가 됨
<DialogTrigger asChild>
<Button>열기</Button>
</DialogTrigger>
// asChild 없음 - 추가 div가 생성됨
<DialogTrigger>
<Button>열기</Button>
</DialogTrigger>
<button>열기</button> (깔끔함)<div><button>열기</button></div> (불필요한 wrapper)따라서 asChild를 사용하면 불필요한 DOM 요소 없이 깔끔한 HTML 구조를 만들 수 있음
dialog.tsx:38 <button> cannot contain a nested <button>.
See this log for the ancestor stack trace.
react-dom-client.development.js:4507 Uncaught Error: Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:
- A server/client branch `if (typeof window !== 'undefined')`.
- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
- Date formatting in a user's locale which doesn't match the server.
- External changing data without sending a snapshot of it along with the HTML.
- Invalid HTML tag nesting.
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
https://react.dev/link/hydration-mismatch
at throwOnHydrationMismatch (react-dom-client.development.js:4507:11)
at beginWork (react-dom-client.development.js:10928:17)
at runWithFiberInDEV (react-dom-client.development.js:872:30)
at performUnitOfWork (react-dom-client.development.js:15677:22)
at workLoopConcurrentByScheduler (react-dom-client.development.js:15671:9)
at renderRootConcurrent (react-dom-client.development.js:15646:15)
at performWorkOnRoot (react-dom-client.development.js:14940:13)
at performWorkOnRootViaSchedulerTask (react-dom-client.development.js:16766:7)
at MessagePort.performWorkUntilDeadline (scheduler.development.js:45:48)- 원인 ⇒ DialogTrigger 안에 Button 컴포넌트를 사용할 때 발생하는 HTML 중첩 문제
= DialogTrigger는 이미 <code>button</code> 요소를 렌더링하는데, 그 안에 또 다른 <code>button</code> 요소인 Button 컴포넌트가 들어가서 발생하는 문제
- 해결 방법 ⇒ DialogTrigger에 asChild prop을 사용
- 코드
```tsx
<Dialog>
<DialogTrigger asChild>
<Button>다이얼로그 열기</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>테스트 다이얼로그</DialogTitle>
<DialogDescription>이것은 Dialog 컴포넌트의 동작을 테스트하는 예시입니다.</DialogDescription>
</DialogHeader>
<div className="mt-4">
<p>여기에 원하는 내용을 넣을 수 있습니다.</p>
</div>
<DialogFooter>
<DialogClose asChild>
<div className="flex gap-2">
<Button variant="primary" outline={true}>
취소
</Button>
<Button variant="primary">확인</Button>
</div>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
```
### 주요 변경사항:
1. **DialogTrigger에 asChild 추가**: 이렇게 하면 DialogTrigger가 자체 <code>button</code>을 렌더링하지 않고, 자식 요소(Button)를 그대로 사용함
2. **DialogClose에도 asChild 추가**: 마찬가지로 닫기 버튼도 중첩을 방지함
3. **Button 컴포넌트 사용**: 커스텀 <code>button</code> 대신 프로젝트의 <code>Button</code> 컴포넌트를 사용
이렇게 하면 HTML 중첩 문제가 해결되고 hydration 오류가 발생하지 않음