๐ช 02. atom() ์์ ์ ๋ณต โ primitive atom ๊ณผ ํต์ฌ ํ
๐ ๊ฐ์
atom() ์์ฑ๋ถํฐ useAtom, useAtomValue, useSetAtom์ ์ฐจ์ด์ ์ ํ ๊ธฐ์ค, debugLabel, onMount๊น์ง atom์ ๋ชจ๋ ๊ฒ์ ํํค์นฉ๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
useAtom,useAtomValue,useSetAtom์ ์ฐจ์ด๋ฅผ ์๊ณ , ์ํฉ์ ๋ง๊ฒ ๊ณจ๋ผ ์ธ ์ ์๋ค.- ๋ ๋ ํจ์ ์์์ atom ์ ์์ฑํ ๋ ์
useMemo๊ฐ ํ์์ธ์ง ์ค๋ช ํ ์ ์๋ค.debugLabel๊ณผonMount๋ฅผ ์ค๋ฌด์์ ์ด๋ป๊ฒ ํ์ฉํ๋์ง ์ ์ ์๋ค.
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐งฉ atom() โ ๊ฐ์ฅ ๋จ์ํ ์ํ ๋จ์
- ๐ฃ ์ธ ๊ฐ์ง ํ โ useAtom / useAtomValue / useSetAtom
- โก ๋ ๋ ํจ์ ๋ด atom ์์ฑ โ useMemo ๊ฐ ํ์์ธ ์ด์
- ๐ท๏ธ debugLabel โ DevTools ์์ atom ์ ์ฐพ๋ ๋ฒ
- ๐ onMount โ atom ์ด ๊ตฌ๋ ๋ ๋ ์ฌ์ด๋ ์ดํํธ ์ฒ๋ฆฌ
- ๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
- ๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
- ๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
- ๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
- ๐ ๋ ์์๋ณด๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 18๋ถ (์ ์ฒด) / ํต์ฌ ํํธ๋ง: 10๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
[atom() ๊ธฐ๋ณธ ์ฌ์ฉ] โ [์ธ ๊ฐ์ง ํ ๋น๊ต] โ [๋ ๋ ๋ด atom ์์ฑ ์ฃผ์] โ [debugLabel & onMount ์ค๋ฌด ํ์ฉ]
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
์ค๋ ์์ฒ ์ด๊ฐ ์ง์ atom ์ ์จ๋ณด๋ ๋ ์ด์ผ.
๐ฃ ์์ฒ : "์ํธ ๋,
useAtom์ด๋useAtomValue๋useSetAtom์ด ์ธ ๊ฐ๊ฐ ๋ค ์๋๋ฐ... ๋ญ ์จ์ผ ํด์? ๊ทธ๋ฅuseAtom์ฐ๋ฉด ์ ๋ผ์?"๐ฆ ์ํธ ๋: "์ธ ์๋ ์์ฃ . ๊ทผ๋ฐ
useAtom์ ๊ฐ์ ๊ตฌ๋ ํด์. ๋ฒํผ์ฒ๋ผ ์ฐ๊ธฐ๋ง ํ๋ ์ปดํฌ๋ํธ์์useAtom์ ์ฐ๋ฉด, atom ์ด ๋ฐ๋ ๋๋ง๋ค ๊ทธ ๋ฒํผ๋ ๊ฐ์ด ๋ฆฌ๋ ๋๋ผ์.useSetAtom์ ๊ฐ์ ๊ตฌ๋ ํ์ง ์์ผ๋๊น atom ์ด ๋ฐ๋์ด๋ ๊ทธ ์ปดํฌ๋ํธ๋ ๋ฆฌ๋ ๋ ์์ด ์กฐ์ฉํ ์์ ์ ์์ด์."๐ฃ ์์ฒ : (๋ฉ๋ชจํ๋ฉฐ) "์... ๊ฐ์ ํ๋ฉด์ ์ ์จ๋ ๋ฆฌ๋ ๋๊ฐ ๋๋ค๋ ๊ฑฐ์ฃ ? ๊ทธ๋ฌ๋ฉด ์ข์์ ๋ฒํผ ๊ฐ์ ๊ฑด
useSetAtom์จ์ผ๊ฒ ๋ค์."
๐งฉ atom() โ ๊ฐ์ฅ ๋จ์ํ ์ํ ๋จ์ ๐ข
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- primitive atom ์ TypeScript ์ ํจ๊ป ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ธํ๋ ๋ฒ์ ์ ์ ์๋ค
- atom ์ ์ด๋์ ์ ์ธํด๋ ๋์ง๋ง, ๋ ๋ ํจ์ ์์ ์ํํ๋ค๋ ๊ฒ์ ์ดํดํ๋ค
๊ธฐ๋ณธ ์ ์ธ
import { atom } from 'jotai'
// ์ซ์
const likeCountAtom = atom(0)
// ๋ฌธ์์ด
const searchKeywordAtom = atom('')
// ๊ฐ์ฒด (TypeScript ์ ๋ค๋ฆญ ๊ถ์ฅ)
const userAtom = atom<User | null>(null)
// ๋ฐฐ์ด
const studyListAtom = atom<Study[]>([])
// boolean
const isModalOpenAtom = atom(false)TypeScript ์ ํจ๊ป ์ธ ๋
interface Study {
id: string
title: string
tags: string[]
likeCount: number
}
// ๐ฆ ์ํธ: "์ ๋ค๋ฆญ์ผ๋ก ํ์
์ ๋ช
์ํด๋๋ฉด IDE ์๋์์ฑ์ด ์๋ฒฝํ๊ฒ ๋์ํด์"
const selectedStudyAtom = atom<Study | null>(null)
const studyFiltersAtom = atom<{
category: string
tags: string[]
sortBy: 'latest' | 'popular'
}>({
category: 'all',
tags: [],
sortBy: 'latest',
})atom ์ ์ธ ์์น
// โ
๋ชจ๋ ์ต์๋จ (๊ถ์ฅ) โ ์์ ์ ์ธ ์ฐธ์กฐ
const searchKeywordAtom = atom('')
// โ
๋ณ๋ ํ์ผ์์ export โ ๋๊ท๋ชจ ์ฑ์์ ๊ถ์ฅ
// atoms/search.ts
export const searchKeywordAtom = atom('')
export const searchResultsAtom = atom<Study[]>([])
// โ ๏ธ ๋ ๋ ํจ์ ๋ด๋ถ โ useMemo ์์ด ์ฐ๋ฉด ๋ฌดํ ๋ฃจํ (๋ค์ ์น์
์์ ์์ธํ)
const Component = () => {
const myAtom = atom('') // โ ๋ ๋๋ง๋ค ์ atom config ์์ฑ
}๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
atom ์ "์ ์ญ ๋ณ์" ์ฒ๋ผ ๋ชจ๋ ์ต์๋จ์ ์ ์ธํ๋ ๊ฒ ๊ธฐ๋ณธ์ด์ผ.
๋จ, ๋ ๋ ํจ์ ์์์๋ ์ธ ์ ์์ด โuseMemo๋ก ๊ฐ์ธ๋ฉด.
๐ฃ ์ธ ๊ฐ์ง ํ โ useAtom / useAtomValue / useSetAtom ๐ข
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ์ธ ํ ์ ์ฐจ์ด๋ฅผ ์ค๋ช ํ๊ณ , ์ํฉ์ ๋ง๊ฒ ๊ณ ๋ฅผ ์ ์๋ค
useAtom์ ํญ์ ์ฐ๋ ๊ฒ ์ ๋นํจ์จ์ ์ธ์ง ์ดํดํ๋ค
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
๋ฒํผ ์ปดํฌ๋ํธ๊ฐ ์์ด. ์ด ๋ฒํผ์ ์นด์ดํธ๋ฅผ ์ฆ๊ฐ์ํค๊ธฐ๋ง ํ๊ณ , ํ์ฌ ์นด์ดํธ๋ฅผ ํ๋ฉด์ ํ์ํ์ง ์์.
์ด ์ปดํฌ๋ํธ์์ ์นด์ดํธ atom ์ ์ด๋ค ํ ์ผ๋ก ๊ตฌ๋ ํด์ผ ํ ๊น?
ํ ๋น๊ตํ
| ํ | ๋ฐํ๊ฐ | ๋ฆฌ๋ ๋ ์กฐ๊ฑด | ์ฌ์ฉ ์ผ์ด์ค |
|---|---|---|---|
useAtom | [value, setter] | ๊ฐ์ด ๋ฐ๋ ๋ | ์ฝ๊ธฐ + ์ฐ๊ธฐ ๋ชจ๋ ํ์ํ ๋ |
useAtomValue | value | ๊ฐ์ด ๋ฐ๋ ๋ | ์ฝ๊ธฐ๋ง ํ์ํ ๋ (๋ทฐ ์ปดํฌ๋ํธ) |
useSetAtom | setter | ๋ฆฌ๋ ๋ ์์ | ์ฐ๊ธฐ๋ง ํ์ํ ๋ (๋ฒํผ, ์ด๋ฒคํธ ํธ๋ค๋ฌ) |
์ฝ๋๋ก ๋น๊ต
const likeCountAtom = atom(0)
// โ ๐ฃ ์์ฒ ์ ์ฝ๋ โ ๋ชจ๋ ๊ณณ์ useAtom ์ฌ์ฉ
// LikeButton ์ ์นด์ดํธ๋ฅผ ํ์ํ์ง ์๋๋ฐ๋ ์นด์ดํธ ๋ณ๊ฒฝ ์ ๋ฆฌ๋ ๋๋จ
const LikeButton = () => {
const [, setLikeCount] = useAtom(likeCountAtom) // value ๋ฅผ ์ ์ฐ๋๋ฐ ๊ตฌ๋
์ค
return <button onClick={() => setLikeCount((c) => c + 1)}>โค๏ธ</button>
}
// โ
๐ฆ ์ํธ์ ์ฝ๋ โ ๋ชฉ์ ์ ๋ง๋ ํ
์ ํ
// ์นด์ดํธ ํ์ ์ปดํฌ๋ํธ โ ์ฝ๊ธฐ๋ง ํ์
const LikeCounter = () => {
const likeCount = useAtomValue(likeCountAtom) // ๊ฐ๋ง ๊ตฌ๋
return <span>{likeCount}</span>
}
// ๋ฒํผ ์ปดํฌ๋ํธ โ ์ฐ๊ธฐ๋ง ํ์, ๋ฆฌ๋ ๋๋ง ๋ฐ์ ์ ํจ!
const LikeButton = () => {
const setLikeCount = useSetAtom(likeCountAtom) // setter ๋ง ๊ฐ์ ธ์ด
return <button onClick={() => setLikeCount((c) => c + 1)}>โค๏ธ</button>
}useSetAtom ์ด ๋ฆฌ๋ ๋๋ฅผ ์ผ์ผํค์ง ์๋ ์ด์
// useSetAtom ์ ๊ฐ(value)์ ๊ตฌ๋
ํ์ง ์์
// โ likeCountAtom ๊ฐ์ด ๋ฐ๋์ด๋ ์ด ์ปดํฌ๋ํธ๋ ๋ฆฌ๋ ๋ ์ ๋จ
const LikeButton = () => {
const setLikeCount = useSetAtom(likeCountAtom)
// ์ฌ๊ธฐ์ likeCount ๊ฐ์ด ์์ โ ๊ตฌ๋
์์ โ ๋ฆฌ๋ ๋ ์์
return (
<button onClick={() => setLikeCount((prev) => prev + 1)}>
์ข์์
</button>
)
}๐ ์ฐ๊ฒฐ ๊ณ ๋ฆฌ
useSetAtom์ผ๋ก ์ฐ๊ธฐ ์ ์ฉ ์ก์ ์ ๋ง๋๋ ํจํด์ 14. ๋๊ท๋ชจ ์ฑ Jotai ์ํคํ ์ฒ ์์ "write-only action atom" ์ผ๋ก ๋ ๋ฐ์ ์์ผ.
์ค๋ฌด ํจํด โ ์ปดํฌ๋ํธ ๋ถ๋ฆฌ
// โ
์์๋ค ์คํฐ๋ ์นด๋ ์ปดํฌ๋ํธ
// ์ญํ ๋ณ๋ก ๋ถ๋ฆฌํด์ ๊ฐ์ ํ์ํ ํ
๋ง ์ฌ์ฉ
// ์นด๋ ๋ณธ๋ฌธ โ ์คํฐ๋ ์ ๋ณด ํ์ (์ฝ๊ธฐ ์ ์ฉ)
const StudyCardBody = ({ studyId }: { studyId: string }) => {
const study = useAtomValue(selectedStudyAtom) // ์ฝ๊ธฐ๋ง
return <div>{study?.title}</div>
}
// ์ข์์ ์นด์ดํฐ โ ์ซ์ ํ์ (์ฝ๊ธฐ ์ ์ฉ)
const LikeCount = () => {
const count = useAtomValue(likeCountAtom) // ์ฝ๊ธฐ๋ง
return <span>{count}</span>
}
// ์ข์์ ๋ฒํผ โ ํด๋ฆญ ์ด๋ฒคํธ ์ฒ๋ฆฌ (์ฐ๊ธฐ ์ ์ฉ)
const LikeButton = () => {
const setCount = useSetAtom(likeCountAtom) // ์ฐ๊ธฐ๋ง, ๋ฆฌ๋ ๋ ์์
return <button onClick={() => setCount((c) => c + 1)}>โค๏ธ</button>
}
// ๋ถ๋ชจ ์ปดํฌ๋ํธ โ ๊ทธ๋ฅ ์กฐํฉ
const StudyCard = ({ studyId }: { studyId: string }) => (
<div>
<StudyCardBody studyId={studyId} />
<LikeCount />
<LikeButton />
</div>
)๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
"์ฝ๊ธฐ๋ง ํ๋ฉดuseAtomValue, ์ฐ๊ธฐ๋ง ํ๋ฉดuseSetAtom, ๋ ๋ค๋ฉดuseAtom."
ํนํ ๋ฒํผ์ฒ๋ผ ๊ฐ์ ํ์ํ์ง ์๋ ์ปดํฌ๋ํธ์useSetAtom์ด ์ ์์ด์ผ.
โก ๋ ๋ ํจ์ ๋ด atom ์์ฑ โ useMemo ๊ฐ ํ์์ธ ์ด์ ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ๋ ๋ ํจ์ ๋ด atom ์์ฑ์ด ์ ์ํํ์ง ์๋ฆฌ๋ฅผ ์ค๋ช ํ ์ ์๋ค
useMemo์useRef์ค ์ด๋ค ๊ฑธ ์จ์ผ ํ๋์ง ํ๋จํ ์ ์๋ค
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
๋ ๋ ํจ์ ์์์const myAtom = atom(0)์ ์ฐ๋ฉด ๋ฌด์จ ์ผ์ด ์๊ธธ๊น?
"๋ ๋๋ง๋ค ์ ๊ฐ์ฒด๊ฐ ๋ง๋ค์ด์ง ๊ฒ ๊ฐ๋ค" ๊น์ง ๋ ์ฌ๋ ธ์ผ๋ฉด ์ถฉ๋ถํด.
๋ฌดํ ๋ฃจํ๊ฐ ๋ฐ์ํ๋ ์๋ฆฌ
// โ ๋ฌดํ ๋ฃจํ ๋ฐ์ ๋ฉ์ปค๋์ฆ
const StudyItem = ({ id }: { id: string }) => {
// 1. ๋ ๋ โ atom config ๊ฐ์ฒด A ์์ฑ
const itemAtom = atom({ id })
// 2. useAtom ์ด "์ atom!" ์ผ๋ก ์ธ์ โ ์ด๊ธฐํ โ ๋ฆฌ๋ ๋ ํธ๋ฆฌ๊ฑฐ
const [item] = useAtom(itemAtom)
// 3. ๋ฆฌ๋ ๋ โ atom config ๊ฐ์ฒด B ์์ฑ (A ์ ๋ค๋ฅธ ์ฐธ์กฐ)
// 4. useAtom ์ด ๋ "์ atom!" โ ์ด๊ธฐํ โ ๋ฆฌ๋ ๋ ํธ๋ฆฌ๊ฑฐ
// 5. ๋ฌดํ ๋ฐ๋ณต...
return <div>{item.id}</div>
}ํด๊ฒฐ์ฑ : useMemo
// โ
useMemo ๋ก atom config ๋ฅผ ์์ ์ ์ธ ์ฐธ์กฐ๋ก ์ ์ง
const StudyItem = ({ id }: { id: string }) => {
// id ๊ฐ ๋ฐ๋ ๋๋ง ์ atom config ์์ฑ
const itemAtom = useMemo(() => atom({ id }), [id])
const [item, setItem] = useAtom(itemAtom)
return <div>{item.id}</div>
}useMemo vs useRef โ ์ธ์ ์ด๋ค ๊ฑธ?
// useMemo: ์์กด์ฑ(deps)์ด ์์ ๋ โ id ๊ฐ ๋ฐ๋๋ฉด ์ atom
const itemAtom = useMemo(() => atom({ id }), [id])
// useRef: ์์กด์ฑ์ด ์์ ๋ (ํ ๋ฒ๋ง ์์ฑ, ์ปดํฌ๋ํธ ์๋ช
์ฃผ๊ธฐ ๋์ ์ ์ง)
const itemAtomRef = useRef(atom({ id }))
const itemAtom = itemAtomRef.current
// ๐ฆ ์ํธ: "์์กด์ฑ์ด ์์ผ๋ฉด useMemo, ์์ผ๋ฉด useRef.
// ์์ฌ์ค๋ฌ์ฐ๋ฉด useMemo ์ฐ๋ ๊ฒ ์์ ํด์."๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
๋ ๋ ํจ์ ์์์atom()์ ์ฐ๋ฉด ๋ฐ๋์useMemo(() => atom(), [deps])๋ก ๊ฐ์ธ์ผ ํด.
๋ชจ๋ ์ต์๋จ์ ์ ์ธํ ์ ์์ผ๋ฉด ๊ทธ๊ฒ ์ ์ผ ์์ ํด.
๐ท๏ธ debugLabel โ DevTools ์์ atom ์ ์ฐพ๋ ๋ฒ ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
debugLabel์ ์ค์ ํด์ ๊ฐ๋ฐ ํ๊ฒฝ์์ atom ์ ์ฝ๊ฒ ์๋ณํ ์ ์๋ค
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
const searchKeywordAtom = atom('')
// DevTools ์์ ์ด๋ฆ์ด ์ ๋ณด์ฌ ๋๋ฒ๊น
์ด ์ด๋ ค์
// โ
debugLabel ์ค์
searchKeywordAtom.debugLabel = 'searchKeyword'
// ๋๋ ์ ์ธ๊ณผ ๋์์
const userAtom = Object.assign(atom<User | null>(null), {
debugLabel: 'currentUser',
})์ค๋ฌด ํจํด โ ์ผ๊ด๋ ๋ค์ด๋ฐ ์ปจ๋ฒค์
// atoms/study.ts
export const studyListAtom = atom<Study[]>([])
studyListAtom.debugLabel = 'study/list'
export const selectedStudyAtom = atom<Study | null>(null)
selectedStudyAtom.debugLabel = 'study/selected'
export const studyFiltersAtom = atom({ category: 'all', tags: [] as string[] })
studyFiltersAtom.debugLabel = 'study/filters'
// ๐ฆ ์ํธ: "๋๋ฉ์ธ/์ญํ ํํ๋ก ์ด๋ฆ ์ง๋ ๊ฒ DevTools ์์ ์ฐพ๊ธฐ ํธํด์.
// ๋์ค์ atom ์ด ์์ญ ๊ฐ ๋ ๋ ์ด ์ต๊ด์ด ๋น๋ฉ๋๋ค."๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
debugLabel์ DevTools ์ฉ ์ด๋ฆํ์ผ. ์ ์ธํ๋ ์ต๊ด์ ๋ค์ด๋ฉด ๋๋ฒ๊น ์๊ฐ์ด ํ ์ค์ด.
๐ onMount โ atom ์ด ๊ตฌ๋ ๋ ๋ ์ฌ์ด๋ ์ดํํธ ์ฒ๋ฆฌ ๐ด
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
onMount๊ฐ ์ธ์ ํธ์ถ๋๋์ง, ์ด๋ค ์ฉ๋๋ก ์ฐ๋์ง ์ดํดํ๋คonMount์ ์ ๋ฆฌ(cleanup) ํจ์๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐํํ๋ ๋ฒ์ ์๋ค
onMount ๋?
// atom ์ด ์ฒ์ ๊ตฌ๋
๋ ๋ ์คํ, unmount ์ ์ ๋ฆฌ ํจ์ ๋ฐํ
const countAtom = atom(1)
countAtom.onMount = (setAtom) => {
console.log('countAtom ์ด ์ฒ์ ๊ตฌ๋
๋จ')
setAtom((c) => c + 1) // ๊ตฌ๋
์ฆ์ ์ด๊ธฐ๊ฐ ์กฐ์ ๊ฐ๋ฅ
return () => {
console.log('countAtom ๊ตฌ๋
์๊ฐ ์์ด์ง') // ์ ๋ฆฌ ํจ์
}
}์ค๋ฌด ์์ โ ์ค์๊ฐ ์๋ฆผ ๊ตฌ๋
// ์๋ฆผ atom โ ๊ตฌ๋
์ WebSocket ์ฐ๊ฒฐ, ํด์ ์ ๋๊ธฐ
const notificationAtom = atom<Notification[]>([])
notificationAtom.onMount = (setNotifications) => {
// ์ฒซ ์ปดํฌ๋ํธ๊ฐ ๊ตฌ๋
ํ ๋ WebSocket ์ฐ๊ฒฐ
const ws = new WebSocket('wss://api.yeongsune.dev/notifications')
ws.onmessage = (event) => {
const notification = JSON.parse(event.data) as Notification
setNotifications((prev) => [notification, ...prev])
}
// ๋ง์ง๋ง ๊ตฌ๋
์๊ฐ ์ฌ๋ผ์ง ๋ ์ฐ๊ฒฐ ํด์
return () => ws.close()
}โ ๏ธ ์ฃผ์์ฌํญ:
onMount๋ ์ฒซ ๋ฒ์งธ ๊ตฌ๋ ์ ๊ฐ ์๊ธธ ๋ ํ ๋ฒ๋ง ํธ์ถ๋ผuseSetAtom๋ง ์ฌ์ฉํ๋ ์ปดํฌ๋ํธ๋ ๊ตฌ๋ ์๋ก ์ทจ๊ธ ์ ๋ผ โonMountํธ์ถ ์ ๋จ- React Strict Mode ์์๋ mount โ unmount โ mount ์์๋ก ๋ ๋ฒ ํธ์ถ๋ ์ ์์ด (์ ๋ฆฌ ํจ์ ๊ตฌํ ์ค์)
๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
onMount๋ "์ด atom ์ ์ฒซ ์๋์ด ์์ ๋ ์คํํ ํ์ ์ฝ๋" ์ผ.
WebSocket, ํ์ด๋จธ, ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๊ฐ์ ๊ตฌ๋ ์์ ๋ก์ง์ ์ด์ธ๋ ค.
๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
โ useAtom called outside of Provider ์๋ฌ
์์ธ: React ์ปจํ
์คํธ ๋ฐ์์ useAtom ํธ์ถ
ํด๊ฒฐ์ฑ :
// ์ปดํฌ๋ํธ ๋ด๋ถ์์๋ง useAtom ํธ์ถํด์ผ ํจ
// ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ๋น๋๊ธฐ ํจ์ ๋ด๋ถ์์ useStore() ์ฌ์ฉโ ๋ ๋๋ง๋ค setter ํจ์ ์ฐธ์กฐ๊ฐ ๋ฐ๋์ด ์์ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋จ
์์ธ: useAtom ์ด ๋ฐํํ๋ setter ๋ ํญ์ ์์ ์ ์ธ ์ฐธ์กฐ๋ฅผ ๊ฐ์ ธ. ๋ฆฌ๋ ๋ ์์ธ์ด ์๋ ๊ฐ๋ฅ์ฑ์ด ๋์ผ๋ ๋ค๋ฅธ props ๋ฅผ ํ์ธํด๋ด.
// useAtom, useSetAtom ์ setter ๋ ์์ ์ ์ฐธ์กฐ (๋งค ๋ ๋๋ง๋ค ๊ฐ์ ํจ์)
const [, setCount] = useAtom(countAtom)
// setCount ๋ ํญ์ ๋์ผํ ์ฐธ์กฐ โ memo ๋ ์์์ props ๋ก ๋๊ฒจ๋ ๋ฆฌ๋ ๋ ์ ์ผ์ด๋จ๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
๐ ์ธ ํ ์ ํ ๊ธฐ์ค ์์ฝ
| ์ํฉ | ํ | ์ด์ |
|---|---|---|
| ๊ฐ ํ์ + ์ํ ๋ณ๊ฒฝ ๋ชจ๋ | useAtom | [value, setter] ๋ฐํ |
| ๊ฐ๋ง ํ์ (๋ทฐ ์ปดํฌ๋ํธ) | useAtomValue | ์ฝ๊ธฐ ์ ์ฉ ๋ช ์, ์ฝ๋ ์๋ ๋ช ํ |
| ํด๋ฆญ/์ด๋ฒคํธ ์ฒ๋ฆฌ๋ง (๋ฒํผ) | useSetAtom | ๊ตฌ๋ ์์ โ ๋ฆฌ๋ ๋ ์์ |
โ ๏ธ ์ ๋ ํ์ง ๋ง ๊ฒ
| ์ํฉ | โ ๋์ ์ | โ ์ข์ ์ |
|---|---|---|
| ๋ ๋ ๋ด atom ์์ฑ | const a = atom(0) inside render | useMemo(() => atom(0), []) |
| ๋ชจ๋ ๊ณณ์ useAtom | ๊ฐ ์ ์จ๋ useAtom | ์ฐ๊ธฐ๋ง ํ๋ฉด useSetAtom |
| debugLabel ์๋ต | ์ด๋ฆ ์๋ atom ๋ค์ | atom.debugLabel = 'study/list' |
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ๐ ๏ธ ์ค๋ฌด ๋๋ ๋ง (์์ฒ ์ ์ ํ)
์์ฒ ์ด๊ฐ ์คํฐ๋ ์นด๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ณ ์์ด. ์ด ์ปดํฌ๋ํธ๋ ์ข์์ ์ซ์๋ฅผ ํ์ํ์ง ์๊ณ , ์ข์์ ๋ฒํผ ํด๋ฆญ ์ ์นด์ดํธ๋ง ์ฆ๊ฐ์์ผ. ์ด๋ค ํ ์ ์จ์ผ ํ ๊น?
- A)
const [likeCount, setLikeCount] = useAtom(likeCountAtom) - B)
const likeCount = useAtomValue(likeCountAtom) - C)
const setLikeCount = useSetAtom(likeCountAtom) - D)
const [, setLikeCount] = useAtom(likeCountAtom)
โ ์ ๋ต: C
๐ก ์์ธ ํด์ค:
- ์๋ฆฌ ์ค๋ช
: ์ปดํฌ๋ํธ๊ฐ ๊ฐ์ ํ์ํ์ง ์์ผ๋ฏ๋ก
likeCountAtom์ ๊ตฌ๋ ํ ํ์๊ฐ ์์ด.useSetAtom์ setter ๋ง ๋ฐํํ๊ณ atom ๊ฐ์ ๊ตฌ๋ ํ์ง ์์์,likeCountAtom์ด ๋ณํด๋ ์ด ์ปดํฌ๋ํธ๋ ๋ฆฌ๋ ๋๋์ง ์์. ๋ถํ์ํ ๋ฆฌ๋ ๋ ์ ๋ก! - ์ค๋ต ํผ๋๋ฐฑ: A, D ๋ value ๋ฅผ ๊ตฌ๋ ํ๊ธฐ ๋๋ฌธ์ likeCount ๊ฐ ๋ฐ๋ ๋๋ง๋ค ์ด ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ผ. ๊ฐ์ ์ ์ฐ๋๋ฐ ๋ฆฌ๋ ๋๋๋ฉด ๋ญ๋น์ผ. B ๋ setter ๋ฅผ ์ ๊ณตํ์ง ์์.
- ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "๋ฒํผ ์ปดํฌ๋ํธ์
useSetAtom." ํ๋ฉด์ ์ซ์๋ฅผ ์ ๋ณด์ฌ์ค๋ค๋ฉด ๊ตฌ๋ ๋ ํ์ง ๋ง.
Q2. ๋น์นธ ์ฑ์ฐ๊ธฐ
์๋ ์ฝ๋์์ ๋ฌดํ ๋ฃจํ๋ฅผ ๋ง๊ธฐ ์ํด ๋น์นธ์ ์ฑ์๋ด:
const StudyFilterChip = ({ tag }: { tag: string }) => {
const tagAtom = ______(() => atom(tag), [tag]) // โ ๋น์นธ
const [isSelected, setIsSelected] = useAtom(tagAtom)
return (
<button onClick={() => setIsSelected((v) => !v)}>
{tag}
</button>
)
}โ
์ ๋ต: useMemo
๐ก ์์ธ ํด์ค:
useMemo ๋ก ๊ฐ์ธ๋ฉด tag ๊ฐ ๋ฐ๋ ๋๋ง ์ atom config ๊ฐ ์์ฑ๋ผ. tag ๊ฐ ๋์ผํ๋ฉด ์ด์ ๊ณผ ๊ฐ์ atom config ๊ฐ์ฒด ์ฐธ์กฐ๋ฅผ ๋ฐํํ๊ธฐ ๋๋ฌธ์ useAtom ์ด "์ atom" ์ผ๋ก ์ฐฉ๊ฐํ์ง ์์. ๋ฌดํ ๋ฃจํ ๋ฐฉ์ง!
๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "๋ ๋ ํจ์ ์ atom() = useMemo ๋ก ๊ฐ์ธ๊ธฐ."
Q3. ์น๊ตฌ์๊ฒ ์ค๋ช ํ๋ค๋ฉด?
useAtomValue์useSetAtom์ ๋ฐ๋ก ๋๋ ์ฐ๋ ์ด์ ๋ฅผ ์น๊ตฌ์๊ฒ ์ค๋ช ํด๋ด.
์์ ๋ต๋ณ:
"๊ฐ์ ํ์ํ๋ ์ปดํฌ๋ํธ์ ๊ฐ์ ๋ฐ๊พธ๋ ์ปดํฌ๋ํธ๋ฅผ ๋๋๋ฉด, ๋ฐ๊พธ๋ ์ชฝ์ ๊ฐ์ด ๋ณํด๋ ๋ฆฌ๋ ๋๊ฐ ์ ์ผ์ด๋๊ฑฐ๋ .
useSetAtom์ setter ๋ง ๊ฐ์ ธ์์ '๊ตฌ๋ '์ ์ ํ๊ธฐ ๋๋ฌธ์ด์ผ. ์ข์์ ๋ฒํผ์ฒ๋ผ ์ซ์๋ฅผ ์ ๋ณด์ฌ์ฃผ๋ ์ปดํฌ๋ํธ๊ฐ ์นด์ดํธ ๋ฐ๋ ๋๋ง๋ค ๋ฆฌ๋ ๋๋ ํ์ ์์์."
๐ก ์ง์ ์ค๋ช ํด๋ดค๋ค๋ฉด: ์ด๋ฏธ ์ถฉ๋ถํ ์ดํดํ ๊ฑฐ์ผ! ๐
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ค๋์ atom ํ
์ธ ์ข
๋ฅ๋ฅผ ์ ๋๋ก ์จ๋ดค๋ค. ์ฌ์ค ์ฒ์์ ๊ทธ๋ฅ useAtom ํ๋๋ก ๋ค ํด๊ฒฐํ๋ ค ํ๋๋ฐ...
์ํธ ๋์ด ๋ด PR ์ ๋จ๊ธด ์ฝ๋ฉํธ: "์์ฒ ๋, ๋ฒํผ ์ปดํฌ๋ํธ์ useAtom ์ฐ์
จ๋๋ฐ, ์ด ์ปดํฌ๋ํธ๋ ์ข์์ ์ซ์๋ฅผ ๋ณด์ฌ์ฃผ์ง ์๋๋ฐ ์ ๊ตฌ๋
์ ํ๊ณ ์์ด์?"
๐ก ์ค๋์ ๊ตํ: "์ฝ๊ธฐ๋ง ํ๋ฉด
useAtomValue, ์ฐ๊ธฐ๋ง ํ๋ฉดuseSetAtom. ๋ ๋ค ํ์ํ ๋๋งuseAtom."
๊ทธ๋ฆฌ๊ณ ๋ ๋ ํจ์ ์์์ atom() ์ฐ๋ค๊ฐ ์ง์ง๋ก ๋ฌดํ ๋ฃจํ๋ฅผ ๊ฒช์๋ค. ํญ์ด ๋ฉ์ถ๊ณ ํฌ ์๋ฆฌ๊ฐ ๋ฌ๋ค... useMemo ๋ก ๊ฐ์ธ๋๊น ๋ฐ๋ก ํด๊ฒฐ๋๋๋ฐ, ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ ๋๋ ์ ๊ทธ๋ฌ๋์ง ๋ฉ๋์ด ๋๋ค.
์ค๋ ์ข ๋ง์ด ํผ๋ฌ์ง๋ง ๊ทธ๋๋ ์ํธ ๋ ๋์ ์ด์๋ค. ๋ด์ผ์ ๋ด๊ฐ ๋จผ์ useSetAtom ์ฐ๋ ๋ชจ์ต ๋ณด์ฌ๋๋ ค์ผ์ง. ํด๊ทผํ๊ณ ํธ์์ ๋ค๋ฌ์ ์ผ๊ฐ๊น๋ฐฅ์ด๋ ์ฌ๋จน๊ณ ๊ฐ์ผ๊ฒ ๋ค. ๐