๐จ 09. ๋ ๋๋ง ์ต์ ํ โ atom ๊ตฌ๋ ์ ์ชผ๊ฐ๋ ๊ธฐ์
๐ ๊ฐ์
useAtomValue ๋ถ๋ฆฌ, selectAtom vs focusAtom vs splitAtom ๋น๊ต, ์ปดํฌ๋ํธ ๋ถ๋ฆฌ ์ ๋ต์ผ๋ก ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ์ ๊ฑฐํฉ๋๋ค.
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ํฐ atom ์ ๊ตฌ๋ ํ ๋ ์ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ด ์๊ธฐ๋์ง ์ค๋ช ํ ์ ์๋ค.
selectAtom,focusAtom,splitAtom์ ์ฐจ์ด์ ์ธ์ ๊ฐ๊ฐ์ ์ฐ๋์ง ํ๋จํ ์ ์๋ค.- ์ปดํฌ๋ํธ ๋ถ๋ฆฌ ์ ๋ต์ผ๋ก ๋ฆฌ๋ ๋๋ง ๋ฒ์๋ฅผ ์ต์ํํ๋ ์ค๊ณ๋ฅผ ํ ์ ์๋ค.
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐ค ์ ๋ ๋๋ง ์ต์ ํ๋ฅผ ์์์ผ ํ๋๊ฐ?
- ๐ ๋ฆฌ๋ ๋๋ง ์์ธ ๋ถ์ โ ํฐ atom ์ ํจ์
- โ๏ธ ์ปดํฌ๋ํธ ๋ถ๋ฆฌ ์ ๋ต โ ๊ฐ์ฅ ๋จผ์ ์๋ํ ๊ฒ
- ๐ญ selectAtom โ ์ฝ๊ธฐ ์ ์ฉ ์ฌ๋ผ์ด์ค
- ๐ฌ focusAtom โ ์ฝ๊ณ ์ธ ์ ์๋ ๋ ์ฆ
- ๐๏ธ splitAtom โ ๋ฐฐ์ด์ ๊ฐ๋ณ atom ์ผ๋ก ๋ถ๋ฆฌ
- โ๏ธ ์ธ ๊ฐ์ง ๋๊ตฌ ์ ํ ๊ธฐ์ค ๋น๊ตํ
- ๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
- ๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
- ๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
- ๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
- ๐ ๋ ์์๋ณด๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 30๋ถ (์ ์ฒด) / ํต์ฌ ํํธ๋ง: 18๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: ์์ ๋์ UX ํผ๋๋ฐฑ
์ด๋ ๋ชฉ์์ผ ์คํ, ์์ ๋์ด ๋์์ธ ๊ฒํ ์ฑ๋์ ๋ฉ์์ง๋ฅผ ๋จ๊ฒผ์ด:
- ๐จ ์์ ๋ (๋์์ด๋): "์์ฒ ๋, ์คํฐ๋ ์นด๋์์ ์ข์์ ๋ฒํผ ํ๋ ๋๋ฅด๋ฉด ์นด๋ ๋ชฉ๋ก ์ ์ฒด๊ฐ ๊น๋นก์ด๋ ๊ฑฐ ๋ง์์? ์คํฌ๋กค ์์น๊น์ง ํ์ด์. ์ด๊ฑฐ ๋ฒ๊ทธ ์๋๊ฐ์?"
- ๐ฃ ์์ฒ : (๋นํฉ) "์... ์๋ ์ด๋ฌ์ง ์์๋๋ฐ์? ์ ๊น๋ง์."
- ๐ฃ ์์ฒ : (์ฝ๋ ์ด์ด๋ณด๊ณ ) "์
studyListAtom์ ์คํฐ๋ ์ ์ฒด ๋ฐ์ดํฐ๊ฐ ๋ฐฐ์ด๋ก ์๋๋ฐ, ์ข์์ ์ ํ๋ ๋ฐ๋๋ฉด ๋ฐฐ์ด ์ ์ฒด๊ฐ ์ ์ฐธ์กฐ๊ฐ ๋๋๊น ์ ์ฒด ๋ชฉ๋ก์ด ๋ฆฌ๋ ๋๋๋ ๊ฑฐ๋ค์..." - ๐ฆ ์ํธ ๋: "๊ทธ๊ฑฐ์์.
splitAtom์ด๋selectAtom์ผ๋ก ์ชผ๊ฐ๋ฉด ํด๋น ์นด๋๋ง ๋ฆฌ๋ ๋๋ผ์. ๊ฐ์ด ๋ณผ๊น์?"
๐ค ์ ๋ ๋๋ง ์ต์ ํ๋ฅผ ์์์ผ ํ๋๊ฐ? ๐ข
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- atom ์ด ๋ฐ๋ ๋ ๋ฆฌ๋ ๋๋ง์ด ์ ํ๋๋ ๋ฒ์๋ฅผ ์ดํดํ๋ค
- ์ธ์ ์ต์ ํ๊ฐ ํ์ํ๊ณ ์ธ์ ์ค๋ฒ ์์ง๋์ด๋ง์ด ๋๋์ง ํ๋จํ ์ ์๋ค
๐ค ์ ๊น, ๋จผ์ ์๊ฐํด๋ด
์คํฐ๋ ๋ชฉ๋ก์ ์นด๋๊ฐ 100๊ฐ ์์ด. ์ฒซ ๋ฒ์งธ ์นด๋์ ์ข์์ ์๋ง ๋ฐ๋์์ด. ๋ช ๊ฐ์ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ ๊ฒ ๊ฐ์?
์์ ๋์ ํผ๋๋ฐฑ์ด ์ ํํ์ด. Jotai ๋ Context ๋ณด๋ค ํจ์ฌ ์ ํ์ ์ผ๋ก ๋ฆฌ๋ ๋๋ฅผ ํธ๋ฆฌ๊ฑฐํ์ง๋ง, atom ์ ์๋ชป ์ค๊ณํ๋ฉด ์ฌ์ ํ ๋ถํ์ํ ๋ฆฌ๋ ๋๊ฐ ๋ฐ์ํด.
๋ฌธ์ ์ํฉ:
studyListAtom = [ study1, study2, ..., study100 ]
study1.likeCount ๊ฐ ๋ฐ๋๋ฉด:
โ studyListAtom ์ ์ฒด ๋ฐฐ์ด ์ฐธ์กฐ ๋ณ๊ฒฝ
โ studyListAtom ์ ๊ตฌ๋
ํ๋ StudyList ์ปดํฌ๋ํธ ๋ฆฌ๋ ๋
โ StudyList ๊ฐ ๋ ๋ํ๋ 100๊ฐ์ StudyCard ๋ชจ๋ ๋ฆฌ๋ ๋
์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ฒ:
โ study1.likeCount ๋ฅผ ๊ตฌ๋
ํ๋ StudyCard[0] ๋ง ๋ฆฌ๋ ๋
Jotai ๊ณต์ ์ฑ๋ฅ ๊ฐ์ด๋๋ ์ด๋ ๊ฒ ๋งํด:
"Jotai ๋ ๋ฐ์ดํฐ๋ฅผ atomic ํ๊ฒ ์ชผ๊ฐ๋๋ก ๊ถ์ฅํ๋ค. ๊ฐ atom ์ ๋ ๋ฆฝ์ ์ผ๋ก ์ ์ฅ๋๊ณ ์์ ์ ๊ฐ์ด ๋ฐ๋ ๋๋ง ๋ฆฌ๋ ๋๋ฅผ ํธ๋ฆฌ๊ฑฐํ๋ค."
๐ก ํ ์ค๋ก ๊ธฐ์ตํ๊ธฐ
"ํฐ atom ํ๋ = ํฌ๋ค ์นดํ ๋จ์ฒด ์๋ฆผ". ๊ณต์ง ํ๋ ์ฌ๋ผ์ค๋ฉด ์นดํ ํ์ ์ ์ฒด๊ฐ ์๋ฆผ ๋ฐ์. atom ์ ์ชผ๊ฐค์๋ก ์๋ฆผ์ด ์ ํํด์ ธ.
๐ ๋ฆฌ๋ ๋๋ง ์์ธ ๋ถ์ โ ํฐ atom ์ ํจ์ ๐ข
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ๊ฐ์ฒด๋ ๋ฐฐ์ด atom ์์ ์ผ๋ถ ํ๋๋ง ๋ฐ๋์ด๋ ์ ์ฒด๊ฐ ๋ฆฌ๋ ๋๋๋ ์ด์ ๋ฅผ ์ค๋ช ํ ์ ์๋ค
// ๐ฃ ์์ฒ ์ด ์ฒ์์ ์ง ๊ตฌ์กฐ โ ์คํฐ๋ ํ๋์ ๋ชจ๋ ์ ๋ณด๋ฅผ ํ๋์ ๊ฐ์ฒด atom ์ผ๋ก
interface Study {
id: string
title: string
description: string
category: string
likeCount: number // ์์ฃผ ๋ฐ๋๋ ํ๋
memberCount: number // ๊ฐ๋ ๋ฐ๋๋ ํ๋
tags: string[] // ๊ฑฐ์ ์ ๋ฐ๋๋ ํ๋
}
// ๐ฃ ์์ฒ : "์ผ๋จ ๋ค ๋ฃ์ด๋์ด์. ํธํ๊ฒ ์ฐ๋ ค๊ณ ์."
const studyAtom = atom<Study>({
id: 'study-1',
title: 'React ์ฌํ ์คํฐ๋',
description: '๋ฆฌ๋ ๋๋ง ์ต์ ํ ์ง์ค ํ๊ตฌ',
category: 'frontend',
likeCount: 42,
memberCount: 8,
tags: ['react', 'jotai', 'typescript'],
})
// ๋ชจ๋ ํ๋๋ฅผ ์ด ํ๋์ ์ปดํฌ๋ํธ์์ ๊ตฌ๋
const StudyCard = () => {
// ๐ฃ ์์ฒ : "์ด๋ ๊ฒ ํ๋ฉด studyAtom ์ ์ด๋ค ํ๋๊ฐ ๋ฐ๋์ด๋ ์ด ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋จ"
const study = useAtomValue(studyAtom)
// โ
// likeCount ๋ง ๋ฐ๋์ด๋ title, description, tags ๋ฑ์ ํ์ํ๋ ๋ถ๋ถ๊น์ง ์ ๋ถ ๋ฆฌ๋ ๋!
return (
<div>
<h2>{study.title}</h2> {/* likeCount ๊ฐ ๋ฐ๋์ด๋ ์ฌ๊ธฐ๋ ๋ฆฌ๋ ๋ */}
<p>{study.description}</p> {/* likeCount ๊ฐ ๋ฐ๋์ด๋ ์ฌ๊ธฐ๋ ๋ฆฌ๋ ๋ */}
<span>โค๏ธ {study.likeCount}</span>
<span>๐ฅ {study.memberCount}</span>
</div>
)
}๋ฌธ์ :
likeCount: 42 โ 43 ์ผ๋ก ๋ณ๊ฒฝ
โ studyAtom ์ value ๊ฐ ์ ๊ฐ์ฒด๋ก ๊ต์ฒด
โ StudyCard ์ ์ฒด ๋ฆฌ๋ ๋
โ title, description, tags ๋ ๋ณํ์ง ์์๋๋ฐ๋ React ๊ฐ ๋ค์ ๊ณ์ฐ
์ด๊ฑด ๋ญ๋น์ผ. 100๊ฐ ์นด๋๋ฉด 100๋ฐฐ ๋ญ๋น.
โ๏ธ ์ปดํฌ๋ํธ ๋ถ๋ฆฌ ์ ๋ต โ ๊ฐ์ฅ ๋จผ์ ์๋ํ ๊ฒ ๐ข
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ํฐ ์ปดํฌ๋ํธ๋ฅผ ์์ ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌํ๋ ๊ฒ๋ง์ผ๋ก๋ ๋ฆฌ๋ ๋ ๋ฒ์๋ฅผ ์ค์ผ ์ ์๋ค๋ ๊ฒ์ ์ดํดํ๋ค
useAtomValue๋ฅผ ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ ํจ๊ณผ์ ์ธ์ง ์ค๋ช ํ ์ ์๋ค
Jotai ๊ณต์ ์ฑ๋ฅ ๊ฐ์ด๋์ ์ฒซ ๋ฒ์งธ ์กฐ์ธ์ "์์ ์ปดํฌ๋ํธ" ์ผ. ๋ณต์กํ ๋๊ตฌ๋ฅผ ์ฐ๊ธฐ ์ ์ ์ปดํฌ๋ํธ๋ฅผ ์ชผ๊ฐ๋ ๊ฒ๋ง์ผ๋ก๋ ํฐ ํจ๊ณผ๋ฅผ ๋ณผ ์ ์์ด.
// โ
Before / After โ ์ปดํฌ๋ํธ ๋ถ๋ฆฌ๋ง์ผ๋ก ์ต์ ํ
// โ Before โ ํ๋์ ํฐ ์ปดํฌ๋ํธ๊ฐ ๋ atom ์ ๋ชจ๋ ๊ตฌ๋
// ๐ฃ ์์ฒ : "์ด๋ ๊ฒ ํ๋ฉด likeCount ๊ฐ ๋ฐ๋ ๋ title ๊น์ง ๋ฆฌ๋ ๋๋ผ์"
const StudyCardBig = () => {
const title = useAtomValue(studyTitleAtom) // ๊ฑฐ์ ์ ๋ฐ๋
const likeCount = useAtomValue(studyLikeAtom) // ์์ฃผ ๋ฐ๋
return (
<div>
<h2>{title}</h2> {/* likeCount ๋ณ๊ฒฝ ์ ์ฌ๊ธฐ๋ ๋ฆฌ๋ ๋ */}
<LikeButton count={likeCount} />
</div>
)
}// โ
After โ ์์ฃผ ๋ฐ๋๋ ๋ถ๋ถ๋ง ๋ณ๋ ์ปดํฌ๋ํธ๋ก ๋ถ๋ฆฌ
// ๐ฆ ์ํธ: "title ๊ณผ likeCount ๋ ๋ณ๊ฒฝ ๋น๋๊ฐ ๋ฌ๋ผ์. ์ชผ๊ฐ๋ ๊ฒ ๋ง์์."
const StudyTitle = () => {
const title = useAtomValue(studyTitleAtom) // title ์ด ๋ฐ๋ ๋๋ง ๋ฆฌ๋ ๋
return <h2>{title}</h2>
}
const StudyLikeButton = () => {
const [likeCount, setLikeCount] = useAtom(studyLikeAtom) // likeCount ๊ฐ ๋ฐ๋ ๋๋ง ๋ฆฌ๋ ๋
return (
<button onClick={() => setLikeCount((c) => c + 1)}>
โค๏ธ {likeCount}
</button>
)
}
// StudyCard ๋ ์ด์ ๋ ์ปดํฌ๋ํธ๋ฅผ ์กฐ๋ฆฝ๋ง ํจ โ ์ง์ atom ๊ตฌ๋
์์
const StudyCard = () => (
<div>
<StudyTitle />
<StudyLikeButton />
</div>
)
// likeCount ๋ณ๊ฒฝ โ StudyLikeButton ๋ง ๋ฆฌ๋ ๋ โ
๐ก ์ปดํฌ๋ํธ ๋ถ๋ฆฌ ์์น
"๋ณ๊ฒฝ ๋น๋๊ฐ ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ์ปดํฌ๋ํธ์ ๋์ง ๋ง๋ผ."
์์ฃผ ๋ฐ๋๋ ๋ถ๋ถ๊ณผ ๊ฑฐ์ ์ ๋ฐ๋๋ ๋ถ๋ถ์ ๋ถ๋ฆฌํ๋ฉด, ์ธ๋ฐ์๋ ๋ฆฌ๋ ๋๋ฅผ ์์ฐ์ค๋ฝ๊ฒ ๋ง์ ์ ์์ด.
๐ญ selectAtom โ ์ฝ๊ธฐ ์ ์ฉ ์ฌ๋ผ์ด์ค ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
selectAtom์ผ๋ก ํฐ atom ์ ํน์ ํ๋๋ง ๊ตฌ๋ ํ๋ ํ์ atom ์ ๋ง๋ค ์ ์๋คequalityFn์ ํ์ฉํด์ ์ฐธ์กฐ๊ฐ ๋ฐ๋์ด๋ ๊ฐ์ด ๊ฐ์ผ๋ฉด ๋ฆฌ๋ ๋๋ฅผ ๋ง๋ ๋ฐฉ๋ฒ์ ์๋ค
์ปดํฌ๋ํธ๋ฅผ ์ชผ๊ฐ๊ธฐ ์ด๋ ค์ด ์ํฉ์์๋ selectAtom ์ผ๋ก ํฐ atom ์์ ํ์ํ ๋ถ๋ถ๋ง ๋ฝ์๋ด๋ "์ฝ๊ธฐ ์ ์ฉ ํ์ atom" ์ ๋ง๋ค ์ ์์ด.
โ ๏ธ ๊ณต์ ๋ ํผ๋ฐ์ค ์ฃผ์์ฌํญ:
selectAtom์ "escape hatch" (ํ์ถ๊ตฌ)๋ก ์ ๊ณต๋ผ. ์์ atom ๋ชจ๋ธ(derived atom) ์ ์ฐ์ ํ๊ณ ,equalityFn์ด๋prevSlice๊ฐ ๊ผญ ํ์ํ ๋๋งselectAtom์ ์จ.
import { selectAtom } from 'jotai/utils'
// ์์๋ค ์ฑ์ ์คํฐ๋ ์์ธ atom (์ ์ฒด ์ ๋ณด)
const studyDetailAtom = atom<Study>({
id: 'study-1',
title: 'React ์ฌํ ์คํฐ๋',
description: '๋ฆฌ๋ ๋๋ง ์ต์ ํ ์ง์ค ํ๊ตฌ',
likeCount: 42,
tags: ['react', 'jotai'],
})
// ๐ฆ ์ํธ: "selectAtom ์ผ๋ก title ๋ง ๊ตฌ๋
ํ๋ ํ์ atom ์ ๋ง๋ค์ด์"
// title ์ด ๋ฐ๋ ๋๋ง ๊ตฌ๋
์ปดํฌ๋ํธ ๋ฆฌ๋ ๋ โ likeCount ๋ณ๊ฒฝ์๋ ๋ฐ์ ์ ํจ
const studyTitleAtom = selectAtom(studyDetailAtom, (study) => study.title)
// likeCount ๋ง ๊ตฌ๋
ํ๋ ํ์ atom
const studyLikeCountAtom = selectAtom(studyDetailAtom, (study) => study.likeCount)
// ์ฌ์ฉ
const StudyTitle = () => {
const title = useAtomValue(studyTitleAtom) // title ๋ณ๊ฒฝ ์์๋ง ๋ฆฌ๋ ๋
return <h2>{title}</h2>
}
const StudyLikeDisplay = () => {
const likeCount = useAtomValue(studyLikeCountAtom) // likeCount ๋ณ๊ฒฝ ์์๋ง ๋ฆฌ๋ ๋
return <span>โค๏ธ {likeCount}</span>
}equalityFn โ ์ฐธ์กฐ๊ฐ ๋ฌ๋ผ๋ ๊ฐ์ด ๊ฐ์ผ๋ฉด ๋ฆฌ๋ ๋ ๋ง๊ธฐ
๋ฐฐ์ด์ด๋ ๊ฐ์ฒด ์ฌ๋ผ์ด์ค๋ฅผ ์ ํํ ๋, ๋งค ๋ ๋๋ง๋ค ์ ์ฐธ์กฐ๊ฐ ์์ฑ๋๋ฉด selectAtom ์ ๊ธฐ๋ณธ ์ฐธ์กฐ ๋น๊ต(Object.is)๊ฐ ํญ์ ๋ค๋ฅด๋ค๊ณ ํ๋จํด์ ๋ฆฌ๋ ๋๊ฐ ๋ฐ์ํด.
import { selectAtom } from 'jotai/utils'
import deepEqual from 'fast-deep-equal' // ๋๋ lodash.isequal
// ๐ฃ ์์ฒ : "tags ๋ฐฐ์ด์ ์ ํํ๋๋ฐ ์ ๊ณ์ ๋ฆฌ๋ ๋๋ผ์?"
// ๐ฆ ์ํธ: "๋ฐฐ์ด์ ๋งค๋ฒ ์ ์ฐธ์กฐ๊ฐ ์๊ฒจ์. equalityFn ์ ์ฃผ๋ฉด ๊ฐ ๋น๊ต๋ฅผ ํด์."
// โ tags ๊ฐ ๊ฐ์ ๋ด์ฉ์ด์ด๋ ์ฐธ์กฐ๊ฐ ๋ฐ๋๋ฉด ๋ฆฌ๋ ๋๋จ
const tagsAtomBad = selectAtom(studyDetailAtom, (study) => study.tags)
// โ
๊น์ ๋น๊ต๋ก ์ค์ ๋ด์ฉ์ด ๋ฐ๋ ๋๋ง ๋ฆฌ๋ ๋
const tagsAtom = selectAtom(
studyDetailAtom,
(study) => study.tags,
deepEqual, // equalityFn: ๊ฐ์ด ๊ฐ์ผ๋ฉด ๋ฆฌ๋ ๋ ์คํต
)์์ ์ ์ธ selector ํจ์ โ ๋ฌดํ ๋ฃจํ ๋ฐฉ์ง
// โ ๏ธ ์ค์: selectAtom ์ ์ปดํฌ๋ํธ ๋ ๋ ํจ์ ์์์ ํธ์ถํ๋ฉด ๋ฌดํ ๋ฃจํ!
const Component = () => {
// โ ๋ ๋๋ง๋ค ์ selectAtom ํธ์ถ โ ์ atom config โ ์ ๊ตฌ๋
โ ๋ฌดํ ๋ฃจํ
const [title] = useAtom(selectAtom(studyDetailAtom, (s) => s.title))
}
// โ
ํด๊ฒฐ์ฑ
1: ๋ชจ๋ ์ต์๋จ์ ์ ์ธ (๊ถ์ฅ)
const titleAtom = selectAtom(studyDetailAtom, (s) => s.title)
// โ
ํด๊ฒฐ์ฑ
2: useMemo ๋ก ๋ฉ๋ชจ์ด์ ์ด์
const Component = () => {
const titleAtom = useMemo(
() => selectAtom(studyDetailAtom, (s) => s.title),
[] // ์์กด์ฑ ์์ผ๋ฉด ๋น ๋ฐฐ์ด
)
const title = useAtomValue(titleAtom)
}
// โ
ํด๊ฒฐ์ฑ
3: useCallback ์ผ๋ก selector ํจ์ ์์ ํ
const selector = useCallback((s: Study) => s.title, [])
const titleAtom = selectAtom(studyDetailAtom, selector)๐ฌ focusAtom โ ์ฝ๊ณ ์ธ ์ ์๋ ๋ ์ฆ ๐ด
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
focusAtom์ดselectAtom๊ณผ ๋ค๋ฅด๊ฒ ์ฐ๊ธฐ๋ ๊ฐ๋ฅํ ์ด์ ๋ฅผ ์ดํดํ๋ค- ์ธ์
jotai-optics๋ฅผ ์ค์นํด์focusAtom์ ์ฐ๋ ๊ฒ ์ ๋ฆฌํ์ง ํ๋จํ ์ ์๋ค
selectAtom ์ ์ฝ๊ธฐ ์ ์ฉ์ด์ผ. ํน์ ํ๋๋ฅผ ์ฝ๊ณ ์ฐ๋ ๋ ์ฆ๊ฐ ํ์ํ๋ฉด focusAtom ์ ์จ.
npm install jotai-optics optics-tsimport { focusAtom } from 'jotai-optics'
interface StudyProfile {
title: string
description: string
settings: {
isPrivate: boolean
maxMembers: number
}
}
const studyProfileAtom = atom<StudyProfile>({
title: 'React ์ฌํ ์คํฐ๋',
description: '๋ฆฌ๋ ๋๋ง ์ต์ ํ ์ง์ค ํ๊ตฌ',
settings: {
isPrivate: false,
maxMembers: 10,
},
})
// settings ๋ง ์ฝ๊ณ ์ธ ์ ์๋ ํ์ atom
// ๐ฆ ์ํธ: "focusAtom ์ ๋ ์ฆ(lens)์ผ. ํน์ ๋ถ๋ถ์ ํ๋ํด์ ์ฝ๊ณ ์ธ ์ ์์ด์."
const settingsAtom = focusAtom(studyProfileAtom, (optic) => optic.prop('settings'))
// ๋ ๊น์ด ๋ค์ด๊ฐ ์๋ ์์
const isPrivateAtom = focusAtom(studyProfileAtom, (optic) =>
optic.prop('settings').prop('isPrivate')
)
// ์ฌ์ฉ ์์
const StudySettings = () => {
// isPrivate ๋ง ๊ตฌ๋
โ title ์ด๋ description ์ด ๋ฐ๋์ด๋ ๋ฆฌ๋ ๋ ์ ๋จ
const [isPrivate, setIsPrivate] = useAtom(isPrivateAtom)
return (
<label>
<input
type="checkbox"
checked={isPrivate}
onChange={() => setIsPrivate((prev) => !prev)}
/>
๋น๊ณต๊ฐ ์คํฐ๋
</label>
)
}selectAtom vs focusAtom ๋น๊ต
// selectAtom โ ์ฝ๊ธฐ ์ ์ฉ
const titleAtom = selectAtom(studyAtom, (s) => s.title)
const title = useAtomValue(titleAtom) // ์ฝ๊ธฐ O
// setTitle(newTitle) // โ ์ฐ๊ธฐ ๋ถ๊ฐ
// focusAtom โ ์ฝ๊ธฐ + ์ฐ๊ธฐ (๋ ์ฆ)
const titleAtom = focusAtom(studyAtom, (optic) => optic.prop('title'))
const [title, setTitle] = useAtom(titleAtom) // ์ฝ๊ธฐ O, ์ฐ๊ธฐ O โ
// setTitle('์ ์ ๋ชฉ') โ studyAtom ์ title ํ๋๋ง ์
๋ฐ์ดํธ๐๏ธ splitAtom โ ๋ฐฐ์ด์ ๊ฐ๋ณ atom ์ผ๋ก ๋ถ๋ฆฌ ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
splitAtom์ผ๋ก ๋ฐฐ์ด atom ์ ๊ฐ๋ณ item atom ๋ฐฐ์ด๋ก ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์๋ค- ๋ฐฐ์ด์ ํ ํญ๋ชฉ์ด ๋ฐ๋ ๋ ํด๋น ํญ๋ชฉ์ ์ปดํฌ๋ํธ๋ง ๋ฆฌ๋ ๋๋๋ ์๋ฆฌ๋ฅผ ์ดํดํ๋ค
์์ ๋์ด ๋ฐ๊ฒฌํ ๋ฒ๊ทธ์ ํต์ฌ์ด ์ด๊ฑฐ์ผ. ์คํฐ๋ ๋ชฉ๋ก ๋ฐฐ์ด์์ ํ ์นด๋์ ์ข์์๋ง ๋ฐ๋๋๋ฐ ๋ชฉ๋ก ์ ์ฒด๊ฐ ๋ฆฌ๋ ๋๋์ด. splitAtom ์ด ํด๊ฒฐ์ฌ์ผ.
import { atom, useAtom, useAtomValue, PrimitiveAtom } from 'jotai'
import { splitAtom } from 'jotai/utils'
// ๋ฐฐ์ด atom
const studyListAtom = atom<Study[]>([
{ id: '1', title: '์์ฒ ์ด์ React ์คํฐ๋', likeCount: 42 },
{ id: '2', title: '์ํธ ๋์ ์ํคํ
์ฒ ์คํฐ๋', likeCount: 100 },
{ id: '3', title: '์์ ๋์ ๋ฐฑ์๋ ์คํฐ๋', likeCount: 23 },
])
// splitAtom ์ผ๋ก ๋ฐฐ์ด์ ๊ฐ๋ณ item atom ๋ฐฐ์ด๋ก ๋ณํ
// ๐ฆ ์ํธ: "studyAtomsAtom ์ [atom<Study>, atom<Study>, atom<Study>] ๋ฅผ ๋ด์ atom ์ด์์"
const studyAtomsAtom = splitAtom(studyListAtom)// ๊ฐ ์คํฐ๋ ์นด๋๊ฐ ์์ ์ atom ๋ง ๊ตฌ๋
const StudyCard = ({ studyAtom }: { studyAtom: PrimitiveAtom<Study> }) => {
// ๐ฆ ์ํธ: "์ด ์ปดํฌ๋ํธ๋ ์๊ธฐ studyAtom ์ด ๋ฐ๋ ๋๋ง ๋ฆฌ๋ ๋๋ผ์"
const [study, setStudy] = useAtom(studyAtom)
const handleLike = () => {
setStudy((prev) => ({ ...prev, likeCount: prev.likeCount + 1 }))
// studyListAtom ์ ํด๋น ํญ๋ชฉ๋ง ์
๋ฐ์ดํธ โ ๋๋จธ์ง ์นด๋๋ ๋ฆฌ๋ ๋ ์ ๋จ!
}
return (
<div>
<h3>{study.title}</h3>
<button onClick={handleLike}>โค๏ธ {study.likeCount}</button>
</div>
)
}
// ๋ชฉ๋ก ์ปดํฌ๋ํธ โ splitAtom ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉ
const StudyList = () => {
// ๐ฃ ์์ฒ : "studyAtomsAtom ์ atom ๋ฐฐ์ด์ ๋ด์ atom ์ด์์. ์ ๊ธฐํ๋ค!"
const [studyAtoms, dispatch] = useAtom(studyAtomsAtom)
return (
<ul>
{studyAtoms.map((studyAtom) => (
<StudyCard
key={`${studyAtom}`} // atom ์์ฒด๋ฅผ key ๋ก ์ฌ์ฉ
studyAtom={studyAtom}
/>
))}
</ul>
)
}splitAtom ์ dispatch ๋ก ๋ชฉ๋ก ์์
// splitAtom ์ dispatch ํจ์๋ ๋ฐํํด โ remove, insert, move ์ก์
์ง์
const StudyList = () => {
const [studyAtoms, dispatch] = useAtom(studyAtomsAtom)
return (
<ul>
{studyAtoms.map((studyAtom) => (
<li key={`${studyAtom}`}>
<StudyCard studyAtom={studyAtom} />
{/* ๊ฐ๋ณ ํญ๋ชฉ ์ญ์ */}
<button onClick={() => dispatch({ type: 'remove', atom: studyAtom })}>
์ญ์
</button>
</li>
))}
{/* ์ ํญ๋ชฉ ์ถ๊ฐ */}
<button onClick={() => dispatch({
type: 'insert',
value: { id: Date.now().toString(), title: '์ ์คํฐ๋', likeCount: 0 },
})}>
์คํฐ๋ ์ถ๊ฐ
</button>
</ul>
)
}keyExtractor โ ์์ ์ ์ธ atom ๋งคํ
// keyExtractor ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐฐ์ด ์์๊ฐ ๋ฐ๋์ด๋ atom ์ด ์ฌ์์ฑ๋์ง ์์
// ๐ฆ ์ํธ: "id ๊ฐ ๊ฐ์ ํญ๋ชฉ์ ๊ฐ์ atom ์ ์ฌ์ฌ์ฉํด์. ์ฑ๋ฅ ํฅ์!"
const studyAtomsAtom = splitAtom(
studyListAtom,
(study) => study.id, // keyExtractor โ ๊ณ ์ ์๋ณ์
)โ๏ธ ์ธ ๊ฐ์ง ๋๊ตฌ ์ ํ ๊ธฐ์ค ๋น๊ตํ ๐ก
๐ฏ ์ด ์น์ ์ ์ฝ๊ณ ๋๋ฉด:
- ์ํฉ์ ๋ฐ๋ผ
selectAtom,focusAtom,splitAtom์ค ์ด๋ค ๊ฒ์ ์ธ์ง ์ฆ์ ํ๋จํ ์ ์๋ค
| ๋๊ตฌ | ์ฝ๊ธฐ | ์ฐ๊ธฐ | ๋์ | ์ธ์ |
|---|---|---|---|---|
| derived atom | โ | โ | ๋จ์ผ ๊ฐ์ฒด ํ๋ | ๊ฐ์ฅ ๊ธฐ๋ณธ, ์ฐ์ ๊ณ ๋ ค |
selectAtom | โ | โ | ๋จ์ผ ๊ฐ์ฒด ํ๋ | equalityFn ์ด ํ์ํ ๋ |
focusAtom | โ | โ | ๋จ์ผ ๊ฐ์ฒด ํ๋ | ํน์ ํ๋๋ฅผ ์ฝ๊ณ ์จ์ผ ํ ๋ |
splitAtom | โ | โ | ๋ฐฐ์ด ๊ฐ ํญ๋ชฉ | ๋ฐฐ์ด์ ๊ฐ๋ณ ํญ๋ชฉ์ ๋ ๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌํ ๋ |
์ ๋ฐ์ดํธ ๋น๋์ ๋ฐ๋ฅธ ์ ํ ๊ธฐ์ค
์์ฃผ ๋ฐ๋๋ ํ๋ (e.g., likeCount, isOnline):
โ ๋ณ๋ atom ์ผ๋ก ๋ถ๋ฆฌ or splitAtom
โ focusAtom ์ overhead ๊ฐ ์์ ์ ์์
๊ฐ๋ ๋ฐ๋๋ ํ๋ (e.g., description, tags):
โ selectAtom with equalityFn (deepEqual)
โ ๋ถํ์ํ ๋ฆฌ๋ ๋ ๋ฐฉ์ง
๊ฑฐ์ ์ ๋ฐ๋๋ ํ๋ (e.g., id, createdAt):
โ ๊ตณ์ด ๋ถ๋ฆฌ ์ ํด๋ ๋จ
โ ๋ถ๋ฆฌํ๋ฉด ์คํ๋ ค ์ฝ๋ ๋ณต์ก๋๋ง ์ฌ๋ผ๊ฐ
๐ก Jotai ๊ณต์ ์ฑ๋ฅ ๊ฐ์ด๋์ ํต์ฌ ์กฐ์ธ
"์์ฃผ ๋ฐ๋๋ ํ๋์ ๊ฑฐ์ ์ ๋ฐ๋๋ ํ๋๊ฐ ๋ ๋ฆฝ์ ์ผ๋ก ๋ณํ๋ค๋ฉดfocusAtom์ด๋selectAtom์ ์จ์ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ฅผ ๋ง์๋ผ. ํ๋๋ค์ด ๋์์ ๋ฐ๋๋ค๋ฉด ๋ถ๋ฆฌํด๋ดค์ overhead ๋ง ์๊ธด๋ค."
๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
์๋ฌ ๋ฉ์์ง๊ฐ ๋จ๋ฉด Ctrl+F ๋ก ๊ฒ์ํด๋ด. ๋๋ถ๋ถ ์ฌ๊ธฐ ์์ด.
โ selectAtom ์ฌ์ฉ ์ ๋ฌดํ ๋ฃจํ
์ฆ์: ์ปดํฌ๋ํธ๊ฐ ๋ฉ์ถ์ง ์๊ณ ๊ณ์ ๋ฆฌ๋ ๋๋จ
์์ธ: ๋ ๋ ํจ์ ์์์ selectAtom() ์ ์ง์ ํธ์ถ
// โ ๋ฌธ์ ์ฝ๋
const Component = () => {
const [title] = useAtom(selectAtom(studyAtom, (s) => s.title)) // ๋ฌดํ ๋ฃจํ!
}ํด๊ฒฐ์ฑ :
// โ
๋ชจ๋ ์ต์๋จ์ ์ ์ธ
const titleAtom = selectAtom(studyAtom, (s) => s.title)
// โ
๋๋ useMemo
const Component = () => {
const titleAtom = useMemo(() => selectAtom(studyAtom, (s) => s.title), [])
const title = useAtomValue(titleAtom)
}โ splitAtom ์์ ํ์ ์๋ฌ
์ฆ์: studyAtom ์ ํ์
์ด PrimitiveAtom<Study> ๊ฐ ์๋๋ผ๊ณ ์๋ฌ
ํด๊ฒฐ์ฑ :
import type { PrimitiveAtom } from 'jotai'
import { splitAtom } from 'jotai/utils'
// keyExtractor ๋ฅผ ์ฐ๋ฉด ํ์
์ถ๋ก ์ด ๋ ๋ช
ํํด์ง
const studyAtomsAtom = splitAtom(studyListAtom, (s) => s.id)
const StudyCard = ({ studyAtom }: { studyAtom: PrimitiveAtom<Study> }) => {
const [study] = useAtom(studyAtom)
return <div>{study.title}</div>
}โ focusAtom ์ ์จ๋ ๋ฆฌ๋ ๋๊ฐ ์ค์ง ์์
์์ธ: ์ ํํ ํ๋๊ฐ ์ฌ์ค ์์ฃผ ๋ฐ๋๋ ํ๋์ฌ์, ์ต์ ํ ํจ๊ณผ๊ฐ ์๋ ์ํฉ
ํด๊ฒฐ์ฑ : ๋ฐ์ดํฐ ํ๋ฆ์ ๋ค์ ์ค๊ณ โ ์์ฃผ ๋ฐ๋๋ ๋ฐ์ดํฐ์ ๊ฑฐ์ ์ ๋ฐ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ์๋ถํฐ ๋ณ๋ atom ์ผ๋ก ๋ถ๋ฆฌ
๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
๐ ๋ ๋๋ง ์ต์ ํ ๋๊ตฌ ์์ฝ
| ์ ๋ต | ๋ณต์ก๋ | ํจ๊ณผ | ์ธ์ |
|---|---|---|---|
| atom ๋ถ๋ฆฌ (์ฒ์๋ถํฐ) | ๋ฎ์ | ๋์ | atom ์ค๊ณ ๋จ๊ณ์์ |
| ์ปดํฌ๋ํธ ๋ถ๋ฆฌ | ๋ฎ์ | ๋์ | ๋ฆฌํฉํ ๋ง 1์์ |
selectAtom | ์ค๊ฐ | ์ค๊ฐ | ํฐ atom ์์ ์ฝ๊ธฐ ์ ์ฉ ์ฌ๋ผ์ด์ค |
focusAtom | ๋์ | ๋์ | ์ฝ๊ณ ์ฐ๋ ๋ ์ฆ๊ฐ ํ์ํ ๋ |
splitAtom | ์ค๊ฐ | ๋์ | ๋ฐฐ์ด ๋ชฉ๋ก ์ต์ ํ |
โ ๏ธ ์ต์ ํ ํจ์
| ์ํฉ | โ ๋์ ์ | โ ์ข์ ์ |
|---|---|---|
| ๋ชจ๋ ํ๋๋ฅผ ๋ฌด์กฐ๊ฑด ๋ถ๋ฆฌ | ๋ณ๊ฒฝ ๋น๋ ๋ฌด๊ดํ๊ฒ ์ ๋ถ selectAtom | ์์ฃผ ๋ฐ๋๋ ํ๋๋ง ๋ถ๋ฆฌ |
| ๋ ๋ ํจ์ ๋ด selectAtom | useAtom(selectAtom(atom, fn)) | ๋ชจ๋ ์ต์๋จ or useMemo |
| ๋ฐฐ์ด ๋ชฉ๋ก ์ต์ ํ ๋ฌด์ | ๋ฐฐ์ด ์ ์ฒด atom ํ๋๋ก ๊ด๋ฆฌ | splitAtom ์ผ๋ก ๊ฐ๋ณ atom ๋ถ๋ฆฌ |
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ๐จ ์ํคํ ์ฒ ์ค๊ณ (์์์ UX ์์๋ฆฌ)
์์ ๋์ด "์คํฐ๋ ๋ชฉ๋ก์์ ์ข์์ ๋ฒํผ ํ๋ ๋๋ ์ ๋ ๋ชฉ๋ก ์ ์ฒด๊ฐ ๊น๋นก์ธ๋ค" ๊ณ ํผ๋๋ฐฑํ์ด.
์์ฒ ์ด๊ฐ ํ์ธํ๋studyListAtom = atom<Study[]>([...])ํ๋๋ก ์ ์ฒด ๋ชฉ๋ก์ ๊ด๋ฆฌํ๊ณ ์์์ด.
์ํธ ๋์ด ์ ์ํ ๊ฐ์ฅ ์ง์ ์ ์ธ ํด๊ฒฐ์ฑ ์?
- A)
React.memo๋กStudyCard๋ฅผ ๊ฐ์ผ๋ค - B)
splitAtom์ผ๋ก ๋ฐฐ์ด์ ๊ฐ๋ณ item atom ์ผ๋ก ๋ถ๋ฆฌํ๊ณ , ๊ฐStudyCard๊ฐ ์์ ์ atom ๋ง ๊ตฌ๋ ํ๋๋ก ํ๋ค - C)
useCallback์ผ๋ก ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฉ๋ชจ์ด์ ์ด์ ํ๋ค - D) ์ข์์ ์๋ฅผ ๋ณ๋ API ๋ก ๋ถ๋ฆฌํด์ ์๋ฒ์์๋ง ๊ด๋ฆฌํ๋ค
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค:
- ์๋ฆฌ ์ค๋ช
:
studyListAtom์ ์ฒด๋ฅผ ๊ตฌ๋ ํ๋ฉด ๋ฐฐ์ด์ ์ด๋ ํญ๋ชฉ์ด ๋ฐ๋์ด๋ ์ ๋ฐฐ์ด ์ฐธ์กฐ๊ฐ ์์ฑ๋๊ณ , ๊ตฌ๋ ์ปดํฌ๋ํธ ์ ์ฒด๊ฐ ๋ฆฌ๋ ๋๋ผ.splitAtom์ ์ฐ๋ฉด ๋ฐฐ์ด์ด[atom<Study>, atom<Study>, ...]๋ก ๋ณํ๋๊ณ , ๊ฐStudyCard๋ ์์ ์๊ฒ ํ ๋น๋ atom ๋ง ๊ตฌ๋ ํด. ํน์ ์นด๋์likeCount๊ฐ ๋ฐ๋๋ฉด ๊ทธ ์นด๋์ atom ๋ง ์ ๋ฐ์ดํธ๋๊ณ , ํด๋นStudyCard์ปดํฌ๋ํธ๋ง ๋ฆฌ๋ ๋๋ผ. - ์ค๋ต ํผ๋๋ฐฑ: A ๋
React.memo๊ฐ prop ๋น๊ต๋ฅผ ํ๋๋ฐ,studyListAtom์ ์ฒด๋ฅผ ๊ตฌ๋ ํ๋ฉด prop ์ด ๋งค๋ฒ ์ ๊ฐ์ฒด๋ผ ํจ๊ณผ๊ฐ ์์ด. C ๋ ์ด ๋ฌธ์ ์ ๋ฌด๊ดํด. D ๋ ์ํคํ ์ฒ ๊ณผ์์ด์ผ. - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "๋ฐฐ์ด ์ต์ ํ =
splitAtom". ๋ชฉ๋ก ์์ดํ ํ๋๊ฐ ๋ฐ๋๋ฉด ๊ทธ ์์ดํ ๋ง ๊นจ์.
Q2. ๐ฆ ์๋์ด ๋ฉด์ ์ง๋ฌธ (์์ฒ ์ ๋ฉด์ ๋์ )
๋ฉด์ ๊ด์ด ๋ฌผ์์ด: "
selectAtom๊ณผ derived atom (๋จ์ ํ์ atom) ์ ์ฐจ์ด๋ ๋ฌด์์ธ๊ฐ์?selectAtom์ ์ธ์ ์ฌ์ฉํ๋์?"
- A)
selectAtom์ ์ฐ๊ธฐ๋ ๊ฐ๋ฅํ๊ณ , derived atom ์ ์ฝ๊ธฐ ์ ์ฉ์ด๋ค - B)
selectAtom์equalityFn์ผ๋ก ์ปค์คํ ๋๋ฑ์ฑ ๋น๊ต๋ฅผ ํ ์ ์์ด์, ๊น์ ๋น๊ต๋ ์ด์ ๊ฐ ์ฐธ์กฐ๊ฐ ํ์ํ ๋ ์ฌ์ฉํ๋ค. ๋จ์ ํ์์ด๋ฉด derived atom ์ด ๋ ๊ถ์ฅ๋๋ค - C)
selectAtom์ด derived atom ๋ณด๋ค ํญ์ ๋น ๋ฅด๋ค - D)
selectAtom์ ๋ฐฐ์ด ์ ์ฉ ์ต์ ํ ๋๊ตฌ์ด๋ค
โ ์ ๋ต: B
๐ก ์์ธ ํด์ค:
- ์๋ฆฌ ์ค๋ช
: ๊ณต์ ๋ ํผ๋ฐ์ค์์
selectAtom์ "escape hatch" (ํ์ถ๊ตฌ) ๋ก ์ ์๋ผ. ๊ธฐ๋ณธ์ ์ผ๋ก๋atom((get) => get(baseAtom).title)๊ฐ์ ์์ derived atom ์ ๊ถ์ฅํด.selectAtom์ ๋ ๊ฐ์ง ๊ฒฝ์ฐ์ ์ ์ฉํด: (1)equalityFnโ ๋ฐฐ์ด/๊ฐ์ฒด ์ฌ๋ผ์ด์ค๋ฅผ ๊น์ ๋น๊ต๋ก ์์ ํํด์ผ ํ ๋, (2)prevSliceโ ์ด์ ์ฌ๋ผ์ด์ค ๊ฐ์ ์ฐธ์กฐํด์ ๊ณ์ฐํด์ผ ํ ๋. - ์ค๋ต ํผ๋๋ฐฑ: A ๋ ํ๋ ค.
selectAtom๋ ์ฝ๊ธฐ ์ ์ฉ์ด์ผ. ์ฐ๊ธฐ๊ฐ ํ์ํ๋ฉดfocusAtom. C ๋ ํญ์ ๋ ๋น ๋ฅธ ๊ฒ ์๋๋ผ ์ํฉ์ ๋ฐ๋ผ ๋ฌ๋ผ. - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "
selectAtom= ํ์ถ๊ตฌ. ํ์์ derived atom ์ ๋ฌธ์ผ๋ก ๋ค์ด๊ฐ๊ณ , ๊น์ ๋น๊ต๊ฐ ํ์ํ ๋๋ง ํ์ถ๊ตฌ๋ฅผ ์จ."
Q3. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธ๋ ์ด๋์คํ (ํ ์ ์ฒด ํ์)
์์ ๋์ด ํ์์์ ๋ฌผ์์ด: "์ปดํฌ๋ํธ ๋ถ๋ฆฌ vs
selectAtom์ค ๋ญ ๋จผ์ ์๋ํด์ผ ํด?"
์ํธ ๋์ด ํ ์ ์ฒด์ ์ค๋ช ํ์ด. ๊ฐ์ฅ ์ ์ ํ ๋ต๋ณ์?
์์ ๋ต๋ณ:
"์ปดํฌ๋ํธ ๋ถ๋ฆฌ๋ฅผ ๋จผ์ ์๋ํด์ผ ํด์. ์ปดํฌ๋ํธ๋ฅผ ์๊ฒ ์ชผ๊ฐ๋ฉด ๊ฐ ์ปดํฌ๋ํธ๊ฐ ์์ ์๊ฒ ํ์ํ atom ๋ง ๊ตฌ๋ ํ๊ฒ ๋ผ์, ๋ณต์กํ ๋๊ตฌ ์์ด๋ ๋ฆฌ๋ ๋ ๋ฒ์๋ฅผ ์ค์ผ ์ ์์ด์.
selectAtom์ ์ปดํฌ๋ํธ๋ฅผ ๋ ์ชผ๊ฐ๊ธฐ ์ด๋ ค์ด ์ํฉ์ด๊ฑฐ๋, ๋ฐฐ์ด/๊ฐ์ฒด ์ฌ๋ผ์ด์ค์equalityFn์ด ํ์ํ ๋ ๋์ ํด์. ๋จผ์ ๋จ์ํ ๊ฒ๋ถํฐ, ํ์ํ ๋๋ง ๋ณต์กํ ๋๊ตฌ๋ฅผ ์จ์ผ ์ฝ๋๊ฐ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์์."
๐ก ํต์ฌ: "๋จ์ํจ ์ฐ์ " ์์น. ๋๊ตฌ๊ฐ ๋ง๋ค๊ณ ๋ค ์จ์ผ ํ๋ ๊ฒ ์๋์ผ.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ค๋ ์์ ๋ ๋๋ถ์ ์ง์ง ์ค์ํ ๊ฑธ ๋ฐฐ์ ๋ค.
์ฌ์ค ์ฒ์์ "๋ญ, ์ข ๊น๋นก์ด๋ ๊ฒ ๋ญ ์ด๋์" ๋ผ๋ ์๊ฐ๋ ์์๋๋ฐ, ์์ ๋์ด "์คํฌ๋กค ์์น๊น์ง ํ์ด์" ๋ผ๊ณ ํ๋ ์๊ฐ ์ง์ง ์ฌ์ฉ์ ์ ์ฅ์์ ์๊ฐํด๋ณด๊ฒ ๋์ด. ๋ด๊ฐ ์ฑ ์ฐ๋ค๊ฐ ๋ชฉ๋ก์ด ๊ณ์ ๊น๋นก์ด๋ฉด ๋๋ ํ๋๊ฒ ๋ค ์ถ์๊ฑฐ๋ .
splitAtom ์ ์ฉํ๊ณ React DevTools ๋ก ํ์ธํ๋๋, ์ข์์ ๋๋ฅธ ์นด๋๋ง ๋
น์์ผ๋ก ๋น๋๋๋ผ. ๋๋จธ์ง ์นด๋๋ค์ ์์ ๋ฆฌ๋ ๋ ์ ๋์ด. ๊ทธ๋ ์ง์ง ๋ฟ๋ฏํ๋ค. ๊ทธ๋ฆฌ๊ณ selectAtom ์ด "ํ์ถ๊ตฌ" ๋ผ๋ ํํ์ด ๋จธ๋ฆฟ์์ ๋ฑ ๋ฐํ์ด. ํ์์ derived atom ์ฐ๊ณ , ๊น์ ๋น๊ต ํ์ํ ๋๋ง selectAtom.
๐ก ์ค๋์ ๊ตํ: "ํฐ atom ์ ํฌ๋ค ์นดํ ๋จ์ฒด ์๋ฆผ์ด๋ค. ์ชผ๊ฐค์๋ก ๋ด๊ฐ ์ํ๋ ๊ฒ๋ง ์๋ฆผ์ด ์จ๋ค."
์์ ๋์ด ์ค๋ ์๊ณ ํ๋ค๊ณ ๋ฉ์์ง๋ ๋ณด๋ด์คฌ์ด. UX ํผ๋๋ฐฑ์ ๋ฒ๊ทธ๋ผ๊ณ ์๊ฐํ์ง ๋ง๊ณ ๊ฐ์ ๊ธฐํ๋ผ๊ณ ์๊ฐํ๋ผ๋ ์กฐ์ธ๋. ๋์์ด๋๋ ๊ฐ๋ฐ์๊ฐ ์ด๋ ๊ฒ ์ ํ๋ ฅํ๋ฉด ์ข์ ๊ฑฐ ๋ง๋ค ์ ์๊ฒ ๋ค ์ถ์์ด.
์ค๋์ ํด๊ทผํ๊ณ ์นํจ ๋จน์ด์ผ์ง. ์ง์ง ์ค๋ ์ง์ค ์ ํ์ผ๋๊น. ๊ต์ด ์์ด์ด๋ ๋ฟ๋งํด์ด๋... ์ด๊ฒ๋ ์ต์ ํ๊ฐ ํ์ํ ์ ํ์ธ๊ฐ?