React

useDialog

Global 다이얼로그 사용에 대한 내용입니다.

Overview

해당 기능은 공통업무 기능입니다. 다음과 같이 미리 준비된 Boilerplate confy-app 형태로 제공됩니다.

주요 설정

Global Provider 설정

/src/shared/provider/customDialogProvider.ts

'use client'
import { DialogContext } from '@/shared/hooks/useDialog'
import { Button, Dialog, Flex, VisuallyHidden } from '@confy-ui/react/themes'
import { ReactNode, useCallback, useState } from 'react'
type DialogHelpers = {
resolve: (v: boolean) => void
close: () => void
}
interface DialogState {
type?: 'alert' | 'confirm'
open: boolean
/** 다이얼로그의 제목(좌측상단 볼드체) */
title?: string
/** 다이얼로그의 본문내용 */
description?: string
/** 컴포넌트 자체를 내려줄 수 있음 */
body?: ReactNode
/** 확인버튼 텍스트(default: 확인) */
confirmText?: string
/** 확인버튼 콜백함수(인자에서 close를 꺼내쓴다_그러지 않고 await처리도 가능) */
onConfirm?: (helpers: DialogHelpers) => void | Promise<void>
/** 취소버튼 텍스트(default: 취소) */
cancelText?: string
/** 취소버튼 콜백함수(인자에서 close를 꺼내쓴다_그러지 않고 await처리도 가능) */
onCancel?: (helpers: DialogHelpers) => void | Promise<void>
resolve: (v: boolean) => void
}
export type ShowDialogArgs = Omit<DialogState, 'open' | 'resolve' | 'id'>
export function DialogProvider({ children }: { children: ReactNode }) {
// ✅ 다이얼로그 스택(여러개 중첩 가능)
const [stack, setStack] = useState<DialogState[]>([])
// ✅ showDialog는 화면에서 사용할 메소드(프로미스 리턴하여 비동기 코드 처리 가능)
const showDialog = useCallback(
({ type, ...args }: ShowDialogArgs): Promise<boolean> => {
return new Promise((resolve) => {
const dialog: DialogState = {
type: type ?? 'alert',
...args,
open: true,
resolve
}
setStack((prev) => [...prev, dialog])
})
},
[]
)
//✅ JSX 리턴
return (
<DialogContext.Provider value={{ showDialog }}>
{children}
{stack.map((dialog, index) => {
const confirmHelpers: DialogHelpers = {
resolve: dialog.resolve,
close: () => {
dialog.resolve(true)
setStack((prev) => prev.slice(0, -1))
}
}
const cancelHelpers: DialogHelpers = {
resolve: dialog.resolve,
close: () => {
dialog.resolve(false)
setStack((prev) => prev.slice(0, -1))
}
}
const handleCancel = () => {
if (dialog.onCancel) {
dialog.onCancel(cancelHelpers)
} else {
cancelHelpers.close()
}
}
const handleConfirm = () => {
if (dialog.onConfirm) {
dialog.onConfirm(confirmHelpers)
} else {
confirmHelpers.close()
}
}
const handleOutsideClick = () => {
setStack((prev) => prev.slice(0, -1))
}
return (
<Dialog.Root key={index} open={dialog.open} onOpenChange={handleOutsideClick} >
<Dialog.Content maxWidth='450px' size='2'>
<Dialog.Title>
{dialog.title ?? (
<VisuallyHidden>
{dialog.description ?? '확인창'}
</VisuallyHidden>
)}
</Dialog.Title>
{dialog.description && (
<Dialog.Description size='2'>
{dialog.description}
</Dialog.Description>
)}
{dialog.body}
<Flex gap='2' mt='4' justify='end'>
{dialog.type === 'confirm' && (
<Button variant='outline' color='gray' onClick={handleCancel}>
{dialog.cancelText ?? '취소'}
</Button>
)}
<Button variant='solid' className='btn primary' onClick={handleConfirm} >
{dialog.confirmText ?? '확인'}
</Button>
</Flex>
</Dialog.Content>
</Dialog.Root>
)
})}
</DialogContext.Provider>
)
}
  • Global Context를 통해 다이얼로그를 관리 합니다
  • useDialog를 통해 Dialog를 생성, 호출 합니다, 호출이 이루어질때마다 Provider의 stack에 다이얼로그를 저장 합니다.
  • 호출 순서의 역순으로 화면에 표시가 먼저 되며, close시 stack에서 제거 됩니다

사용법

import { useDialog } from '@/shared/hooks/useDialog'
import { Button } from '@confy-ui/react/themes'
export default function Page2() {
const showDialog = useDialog()
const onClickButton = (data: { name: string; email: string }) => {
const tf = await showDialog({ description: 'Index 3) 모달_Cancel' })
if (tf) {
console.log('확인')
} else {
console.log('취소')
}
}
return (
<Button onClick={onClickButton}>show dialog</Button>
)
}
  • useDialog 사용시 확인 취소 값을 boolean값으로 리턴 해줍니다
  • options을 통해 alert 타입과 confirm 타입을 선택 가능 합니다
PropTypeDefault
type
enum
alert
title
string
No default value
description
string
No default value
body
ReactNode
No default value
confirmText
string
확인
cancelText
string
취소