Skip to main content

useConfirm

window.confirm시 뜨는 모달을 직접 커스텀해서 유사하게 구현한 hooks입니다.

Prerequisite

npm install recoil
services/store/index.ts
import type { ReactNode } from 'react'
import { atom, useRecoilState, useResetRecoilState } from 'recoil'

const confirmState = atom<{ content: ReactNode; isOpen: boolean }>({
key: 'confirmState',
default: {
content: '',
isOpen: false
}
})
services/hooks/index.tsx
let confirmCb: any
const useConfirm = () => {
const [state, setState] = useRecoilState()
const resetState = useResetRecoilState()

const onConfirm = () => {
confirmCb(true)
resetState()
}

const onCancel = () => {
confirmCb(false)
resetState()
}

const confirm = (content: ReactNode): Promise<any> => {
setState({ content, isOpen: true })
return new Promise((resolve, reject) => {
confirmCb = resolve
})
}

return {
confirm,
onConfirm,
onCancel,
confirmState: state,
resetConfirmState: resetState
}
}
containers/Modal/Confirm/index.tsx
import type { FC } from 'react'
import { Modal } from 'containers'
import { useConfirm } from 'services'

interface Props {}

const ConfirmModal: FC<Props> = () => {
const { onConfirm, onCancel, content, confirmState, resetConfirmState } =
useConfirm()
if (!confirmState.isOpen) return null
return (
<Modal
isOpen={confirmState.isOpen}
onClose={resetConfirmState}
maxWidth="max-w-sm"
>
<div className="p-4">
<div>{content}</div>
<div className="flex justify-between">
<button onClick={onCancel}>아니오</button>
<button onClick={onConfirm}></button>
</div>
</div>
</Modal>
)
}

export default ConfirmModal

Settings

containers/Modal/index.tsx
...
import type { FC } from 'react'
import ConfirmModal from './Confirm'

interface Props {}
interface IModal extends FC<Props> {
Confirm: typeof ConfirmModal
}

const Modal: IModal = () => {
return ...
}

Modal.Confirm = ConfirmModal

export default Modal

Next.js

pages/_app.tsx
import App from 'next/app'
import { Modal } from 'containers'

class MyApp extends App {
render() {
const { Component, pageProps } = this.props
return (
<>
<Component {...pageProps} />
<Modal.Confirm />
</>
)
}
}

export default MyApp

React

src/App.tsx
import { ConfirmModal } from 'containers'

const App = () => {
return (
<>
<div>Create React App</div>
<ConfirmModal />
</>
)
}

export default App

Usage

import { useConfirm } from 'services'

const Page = () => {
const { confirm } = useConfirm()

const handleConfirm = async () => {
try {
const isConfirmed = await confirm('작성을 중단하시겠습니까?')
console.log('isConfirmed', isConfirmed)
} catch (err) {
console.log(err)
}
}

return (
<div>
<button onClick={handleConfirm}>Confirm</button>
</div>
)
}