๊ธฐํ ๋จ๊ณ์์ PM๋๊ณผ ๋์์ด๋๋๊ณผ ํจ๊ป ์์ํ ๋๋ถํฐ ์ฌ์ฉ์์ ์ ์ฅ์์ ํ๋ซํผ์์ ์ฌ์ฉ์ฑ์ด ์ข๊ฒ ๋๊ปด์ง๊ฒ ํ๋ ค๋ฉด ์ด๋ค ๋ฐฉ์์ผ๋ก ์ ๊ณตํ ์ ์์๊น๋ฅผ ๋ง์ด ๊ณ ๋ฏผํ ์ ์์๋ค.
๊ทธ ๊ณผ์ ์์ ์ ์ ๊ฐ ์ด๋ ต๊ฒ ๋๊ปด์ง ์ ์์ ๋ฒํ ๋ถ๋ถ์์ ํดํ์ด๋ ํ ์คํธ๋ฅผ ์ด์ฉํด์ ๋ฐฉ๋ฒ์ ์ ์ ํ ์ ์ํด์ฃผ๊ธฐ๋ก ํ๋๋ฐ, ๋ฌธ์ ๋ ๋ค๋ฅธ ๋ถ๋ค์ด ์ค๋ต๋ฐ์ ํ ์คํธ, ํดํ ๋ชจ๋ ํผ์ฉํด์ ์๋๋ฅผ ์ฐ๋ค๋ณด๋ ๋ค ๋ชจ๋ฅด๋ ๋๋.. ์ด๊ฒ ๋ญ์ง ๐ฑ ??! ์ํ๊ฐ ๋์๋ค.
๊ทธ๋์ ๊ณต๋ถํ๋ค.....
์ฌ์ฉ์ ์ํธ์์ฉ์ผ๋ก ์ ๊ณตํ ์ ์๋ ์๋ฆผ์ฐฝ์ ์ข ๋ฅ๋ ์ด์ ๋๋ก ์ฐพ์๋ดค๋ค.
| ์ค๋ช | ์ฌ์ฉ ์์ | |
| Dialog | ์ฌ์ฉ์์ ์ค์ํ ์ํธ์์ฉ์ ์ํ ์น ํ์ด์ง ๋ด๋ถ์์ ์์ฑ๋๋ ์ปดํฌ๋ํธ. ์ฌ์ฉ์๊ฐ ์ฒ๋ฆฌํ๊ธฐ ์ ๊น์ง๋ ์ฌ๋ผ์ง์ง ์๋๋ค. |
์ ๋ณด ์ ๋ ฅ, ์ญ์ ํ์ธ |
| Toast | ์ฌ์ฉ์์ ๋์์ ์ํ ํผ๋๋ฐฑ์ ๊ฐ๋จํ ui๋ก ๋ณด์ฌ์ฃผ๊ณ ์ฌ๋ผ์ง๋ ์์ pop-up ํํ์ ๋ฐ. | ์ ์ก ์๋ฃ, N๊ฐ ์ด์์ ์ ํํ ์ ์์ต๋๋ค |
| Snackbar | Toast์ ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ , ์ถ๊ฐ์ ์ธ ์ํธ์์ฉ์ ํ ์ ์๋ ์ก์ ๊ธฐ๋ฅ (๋ฒํผ) ์ด ์๋ ๋ฐ. | (์น์ฌ์ดํธ ์ ๊ทผ์) ์ฟ ํค ์ ์ฑ ์ผ๋ถ ์ฟ ํค ์ฐจ๋จํ๊ธฐ ๋ชจ๋ ํ์ฉ |
| Tooltip | ํน์ ์์ญ์ ์ปค์๋ก hover์ ๋ํ๋๋ ํด๋น ์์ญ์ ๋ํ ์ ๋ณด ๋ฐ์ค. | ๋ฒํผ ๊ธฐ๋ฅ ์ค๋ช |
| Alert | ์ฌ์ฉ์์๊ฒ ๊ฒฝ๊ณ ๋ ์ค์ํ ์๋ฆผ์ ์ ๋ฌํ๋ ์์คํ ๋๋ ์ปค์คํฐ๋ง์ด์ง ๋ฐ์ค. | ์ค๋ฅ ๋ฉ์ธ์ง |
n๋ ๊ฐ์ ์ผํ๊ฒฝ๋ ฅ์ผ๋ก ์ดํดํ๊ธฐ ์ฌ์ ๋ค.
์๋ผ์์ ๋์ค๋ ์ฟ ํค ํ์ฉ ์ ์ฑ ์ด์ฉ๊ณ ๊ฐ ์ค๋ต๋ฐ๊ตฌ๋... ์น์ฌ์ดํธ์์ ์๋ฆผ ๋์๋ค๊ฐ ์๋์ผ๋ก ์ฌ๋ผ์ง๋ ๊ฒ ํ ์คํธ์๊ตฌ๋...
๊ทธ๋ ๊ฒ ๊ธฐํ์ ๋ง์น๊ณ ํ ์คํธ๋ฅผ ๋ฐ๋ก ์ ์ฉํ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐพ์๋ณด๋ ๋๋ถ๋ถ react-toastify, ํน์ react-hot-toast๋ฅผ ์ฌ์ฉํ๋ค.
๊ทธ๋ฐ๋ฐ๋ react-hot-toast๋ฅผ ์ฌ์ฉํ ์ด์ ๋ react-toastify๊ฐ ์ฌ์ฉ๋ฅ ์ด ๋๊ธฐ๋ ํ์ง๋ง ๋์จ ๋์์ธ์ด react-hot-toast์ ui์ ๋ ์ ํฉํ๊ธฐ ๋๋ฌธ์ด์๋ค.
react-toastify๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํ๋ฉด ์ค๋ต๋ฐ๋ก ์ด์ฉํ ๋ ๋ ์ ํฉํ๋ค๊ณ ์๊ฐํ๋๋ฐ, ์ดํ ํ ์คํธ์ ๊ธฐ๋ฅ์ด ํ์ฅ๋ ๊ฐ๋ฅ์ฑ์ด ์์ด์ react-hot-toast๋ก ๊ฒฐ์ ํ๋ค.
์ฐพ์๋ณด๋ ์ปค์คํฐ๋ง์ด์ง์ด๋ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ๋น์ทํด์, toastify๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํด๋ ์ด๋ ต์ง ์๊ฒ ์ฌ์ฉํ ์ ์์ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค.
๋ค์๊ณผ ๊ฐ์ด ์์ ํ์ด์ง์์ <Toaster /> ์ ์ธํ๊ณ ํ ์คํธ๋ฅผ ๋ถ๋ฅผ ํ์ ์ปดํฌ๋ํธ์์ toast() ๋ก ํธ์ถํ๋ฉด ๋๋ค.
import { Toaster } from 'react-hot-toast'
export default function Page({
params: { userId, type, messageId },
}: {
params: { userId: string; type: MessageType; messageId: string }
}) {
return (
<div>
// <div> Header... </div>
<ReactionPage messageType={type} userId={userId} messageId={messageId} />
<Toaster
position='bottom-center'
containerStyle={{
bottom: '100px',
}}
/>
</div>
)
}
toast('๋ฐ์์ ์ต๋ 5๊ฐ ๋ณด๋ผ ์ ์์ด์', {
icon: (
<Image
src='/toast_alert.svg'
alt='toast_alert'
width={18}
height={18}
/>
),
style: {
borderRadius: '16px',
backgroundColor: '#474747',
width: '100%',
height: '56px',
paddingLeft: '3.8rem',
paddingRight: '3.2rem',
},
})
๊ทธ๋ผ ๋ค์๊ณผ ๊ฐ์ด ui๊ฐ ๋์จ๋ค.

๊ทธ๋ฐ๋ฐ ๊ฐฏ์ ์ ํ์ฒ๋ฆฌ ์์ด ์ด๋ฒคํธ๋ง ๊ฑธ์ด๋๋ฉด

ใ ใ ;; ์ด์ ์ฌ๊ธฐ์ ํ ์คํธ ๊ฐฏ์ ์ ํ์ ๊ฑธ์ด์ค๋ค.
์ฌ๊ธฐ์ ๋ ์ค์ ํ ์กฐ๊ฑด์ ์ ๋ฆฌํด๋ณด๋ฉด
- 5๊ฐ ์ด๊ณผ ์ ํ๋๋ฉด ํ ์คํธ
- ํ๋ฉด์๋ ์ต๋ 2๊ฐ๊น์ง ๋ณด์ฌ์ง๋ค.
- 5๊ฐ ์ ํ๋ ์ํ์์ ์ด๋ฏธ ์ ํ๋ ๋ ์์ ๋๋ฅด๋ฉด set์์ delete๋ง ๋๊ณ ํ ์คํธ์ ์ํฅ์ ๋ผ์น๋ฉด ์๋๋ค.
const [selectedSet, setSelectedSet] = useState<Set<string>>(new Set())
const [toastVisible, setToastVisible] = useState(false)
const storedData = (templateId: string): Set<string> => {
setToastVisible(false)
setSelectedSet((prevSet) => {
const newSet = new Set(prevSet)
if (newSet.has(templateId)) {
newSet.delete(templateId)
} else {
if (newSet.size < 5) {
newSet.add(templateId)
} else {
setToastVisible(true)
}
}
return newSet
})
return selectedSet
}
useEffect(() => {
if (toastVisible) {
toast('๋ฐ์์ ์ต๋ 5๊ฐ ๋ณด๋ผ ์ ์์ด์', {
icon: (
<Image
src='/toast_alert.svg'
alt='toast_alert'
width={18}
height={18}
/>
),
style: {
borderRadius: '16px',
backgroundColor: '#474747',
width: '100%',
height: '56px',
paddingLeft: '3.8rem',
paddingRight: '3.2rem',
},
})
} else {
setToastVisible(false)
}
}, [selectedSet, toastVisible])
์ ํ๋ ์ด๋ชจ์ง๋ค์ set ํ์ ์ผ๋ก ๊ฑธ์ด์ ์ฌ์ด์ฆ๋ก ๊ฐฏ์๋ฅผ ํ์ธํ๊ณ , ์ดํ ์ด set ๋ฐ์ดํฐ๋ค์ postํ ๋๋ array๋ก ๋ณํํด์ ๋ณด๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ณ ๋ฏผ์ด์๋ ๊ฒ์ด ์์ ๋๋ ๋์์ ํ ์คํธ๊ฐ ํ๋์ฉ ๋จ๋ ๊ฑฐ์๋๋ฐ 2๊ฐ์ฉ ๋จ๋ ๊ฒ์ด์๋ค.
์ฝ์๋ก ์ฐ์ด๋ณด๋ ๋ฆฌ์กํธ์ ๋ ๋๋ง ๋๋ฌธ์ ์ผ์ด๋๋ ๊ฒ ๊ฐ์๋๋ฐ, ์์ ํ์ด์ง์์ <Toaster /> ํ ์คํธ์ ๋ฆฌ๋ฏธํธ ๊ฐฏ์๋ฅผ ์ค์ ํ๊ณ useEffect๋ก ์ด ๋ฆฌ๋ฏธํธ๋ฅผ ๋์ด๊ฐ๋ ํ ์คํธ๋ค์ ๋ํด toast.dismiss()๋ฅผ ์ํํ๋๋ก ํ๋ค.
dismiss ๋ฉ์๋๋ react-hot-toast docs์์ ์ฐพ์๋ณผ ์ ์์๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ด toastOptions์ style๋ก ์ค์ ํ๋ฉด ํ์ ์ปดํฌ๋ํธ์์ ์ ์ฉ๋๋ ํ ์คํธ์ ์ค๋ณต๋๋ ์คํ์ผ๋ค์ ํ๋ฒ์ ์ ์ฉ์ํฌ ์ ์์๋ค.
import toast, { Toaster, useToasterStore } from 'react-hot-toast'
export default function Page({
params: { userId, type, messageId },
}: {
params: { userId: string; type: MessageType; messageId: string }
}) {
const router = useRouter()
const { toasts } = useToasterStore()
const toastLimit = 1
useEffect(() => {
const visibleToasts = toasts.filter((t) => t.visible)
if (visibleToasts.length > toastLimit) {
visibleToasts.slice(toastLimit).forEach((t) => toast.dismiss(t.id))
}
}, [toasts])
return (
<div>
...
<Toaster
position='bottom-center'
containerStyle={{
bottom: '100px',
}}
toastOptions={{ // <- !!
style: {
borderRadius: '16px',
backgroundColor: '#474747',
width: '100%',
height: '56px',
},
}}
/>
</div>
)
}
์ ์ฉ ์์ > https://youtu.be/X5MTjK7DrEc
'What I Learn' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| Lottie๋ก ์ชฝ์ง ์ธ๋ค์ผ์ ์ ์ฉํ๊ธฐ (0) | 2024.12.10 |
|---|---|
| TanStack Query์ ํจ๊ป ๊ตฌํํ cursor ๋ฐฉ์์ ๋ฌดํ ์คํฌ๋กค (1) | 2024.12.10 |
| scroll ์ด๋ฒคํธ๋ฅผ ์ฌ์ฉํ ๋ฌดํ ์คํฌ๋กค ๊ตฌํ (1) | 2024.10.27 |
| Next.js ๋ณ๋ ฌ ๋ผ์ฐํ & ๊ฒฝ๋ก ๊ฐ๋ก์ฑ๊ธฐ๋ฅผ ํตํ ๋ชจ๋ฌ ํ์ด์ง ๊ตฌํ (1) | 2024.10.27 |
| OSSCA: LLM ์กฐ์ฌ, Continue ๋ถ์ ๋ฐ ์ ๋ฆฌ (8) | 2024.10.24 |
