recoil ์ด์ฉํ๊ธฐ
๐์์ํ๋ฉฐ
Flux ํจํด์ ์ฌ์ฉํ๋ React๋ ์ ์ฒด์ ์ผ๋ก ์ํ๋ฅผ ๊ณต์ ํ๊ธฐ ์ํด์ ์ ์ญ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(ํน์ ๊ทธ๊ฒ์ ๋์์ฃผ๋ ๋ฌด์ธ๊ฐโฆ)๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค. ์ด๋ฅผ ์ํด ์ฒ์ React ํ๋ก์ ํธ์์๋ Redux๋ฅผ ์ฌ์ฉํ๊ณ , ๊ทธ ๋ค์ ํ๋ก์ ํธ๋ ๋น๊ต์ ๊ฐ๋จํ ์ํ ๊ด๋ฆฌ๊ฐ ํ์ํด Context API๋ฅผ ์ฌ์ฉํ๋ค.
์ฌ์ค Context API๋ฅผ ์ฌ์ฉํ ํ๋ก์ ํธ๋ ์ด๋ฐ์ Redux๋ฅผ ์ฌ์ฉํ ๊น? ์ถ๋ค๊ฐ๋ ์๋ฌด๋๋ Redux๋ณด๋จ Context API๊ฐ ์์ฑํ๋ ๋ฐฉ๋ฒ๋ ์ฝ๊ณ , ๊ฐ๋จํ๋ค๋ณด๋ Context API๋ฅผ ์ฌ์ฉํ์๋ค.
์๋ก ์ด ๊ธธ์๋ค. ์ด์จ๋ Redux๊ฐ React์ ํจ๊ป ์ํ๊ด๋ฆฌ๋ฅผ ์ํด ์์ฃผ ์ฌ์ฉ๋๋ ๊ฒ์ ๋ง์ง๋ง, ์๋ฌด๋๋ ํ์ต๊ณก์ ์ด ๊ฐํ๋ฅด๊ณ , ์์ฑํด์ผ ํ ๊ฒ๋ ๋ง๋ค ๋ณด๋ ์๋ก์ด ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐพ๊ฒ ๋์๊ณ , ๊ทธ๋ ๊ฒ Recoil
์ ๋ง๋๊ฒ ๋์๋ค.
โ Recoil
๋ฆฌ์ฝ์ผ ํ์๊ณผ ๊ด๋ จํ์ฌ, ๊ณต์๋ฌธ์์ ์ค๋ช ์ ์ฝ์ด๋ณด์. (์์ญ ์์!)
(์ํ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ๋) ํธํ์ฑ๊ณผ ๋จ์์ฑ์ ์ํด ์ธ๋ถ ์ ์ญ ์ํ๋ณด๋ค๋ React์ ๋ด์ฅ๋ ์ํ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ง๋ง React์๋ ๋ช ๊ฐ์ง ํ๊ณ๊ฐ ์์ต๋๋ค.
์ปดํฌ๋ํธ ์ํ๋ ๊ณตํต ์กฐ์์ผ๋ก ์ฌ๋ ค ์ค ๋ค์, ๊ณต์ ํ ์ ์์ง๋ง, ์ฌ๊ธฐ์๋ ๊ทธ ์ํ๋ฅผ ๋ค์ ๋ ๋๋งํด์ผ ํ๋ ํฐ ํธ๋ฆฌ๋ฅผ ํฌํจํ ์ ์์ต๋๋ค.
- ์ปจํ ์คํธ๋ ๋ฌดํํ ๊ฐ์ ์งํฉ์ด ์๋๋ผ, ์ค์ง ๋จ์ผ ๊ฐ๋ง์ ์ ์ฅํ ์ ์์ต๋๋ค.
- ์ด ๋ ๊ฐ์ง ๋ฌธ์ ์ ์, ์ํ๊ฐ ์กด์ฌํด์ผ ํ๋ ํธ๋ฆฌ์ ๋งจ ์ ๋ถ๋ถ(์ํ๊ฐ ์์ด์ผ ํ๋ ๊ณณ)์ ์ฝ๋๋ก ๋ถํ ํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค๊ณ , ํธ๋ฆฌ์ ๋ง๋จ(์ํ๊ฐ ์ฌ์ฉ๋๋ ๊ณณ)์ ์ฝ๋๋ก ๋ถํ ํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค.
(๋ฐ๋ผ์) ์ฐ๋ฆฌ๋, API ๋ฐ ์๋ฏธ์ ๋์์ ๊ฐ๋ฅํ ํ React ์ค๋ฝ๊ฒ ์ ์งํ๋ฉด์ ์ด๋ฅผ ๊ฐ์ ํ๊ณ ์ ํฉ๋๋ค.
์ฆ ์ฝ๊ฒ ๋งํด, react ๋ด๋ถ์ Conexxt api์ ๋จ์ ์ ๊ฐ์ ํ๊ณ , โreactโ์ค๋ฝ๊ฒ ์ ์ญ์ ์ผ๋ก ์ํ๊ด๋ฆฌ๋ฅผ ํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋ ๊ฒ!๐
โ ๊ธฐ๋ณธ ๊ฐ๋
Recoil์ atoms
(๊ณต์ ์ํ)์์ selectors
(์์ ํจ์)๋ฅผ ํตํด ํ๋ฅด๋ ๋ฐ์ดํฐ ํ๋ฆ ๊ทธ๋ํ๋ฅผ ์์ฑํ ์ ์๊ฒ ํด์ฃผ๋ฉฐ, ์ด๋ฅผ React ์ปดํฌ๋ํธ๋ก ๋ด๋ ค๋ณด๋ธ๋ค. atoms
๋ ์ปดํฌ๋ํธ๊ฐ ๊ตฌ๋
ํ ์ ์๋ ์ํ์ ๋จ์์ด๋ฉฐ, selectors
๋ ์ด ์ํ๋ฅผ ๋๊ธฐ์ ๋๋ ๋น๋๊ธฐ์ ์ผ๋ก ๋ณํํ๋ค.
๊ทธ๋ผ ์์ ๋ฅผ ๋ณด๋ฉด์ ์ข๋ ์ดํดํด๋ณด์!
โ ์ค์น
์ค์นํด์ฃผ๊ณ , ์ต์์ ์์์ RecoilRoot
๋ฅผ ๊ฐ์ธ์ฃผ์.
1
yarn add recoil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from "react"
import {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
} from "recoil"
function App() {
return (
<RecoilRoot ๐>
<CharacterCounter />
</RecoilRoot>
)
}
โก๏ธeslint ์ค์
ํ๋ก์ ํธ์์ eslint-plugin-react-hook
์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑํ ์ ์๋ค.
additionalHooks ๋ชฉ๋ก์ โuseRecoilCallbackโ์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข์๋ฐ, useRecoilCallback()
์ ์ ๋ฌ๋ ์ข
์์ฑ์ด ์๋ชป ์ง์ ๋๋ฉด, ESLint๊ฐ ๊ฒฝ๊ณ ํด์ฃผ๋ฉด์, ์์ ์ฌํญ์ ์ ์ํ๊ธฐ ๋๋ฌธ์ด๋ค. (additionalHooks์ ํ์์ ์ ๊ท์ ๋ฌธ์์ด์ด๋ค.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// modified .eslint config
{
"plugins": [
"react-hooks"
],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": [
"warn", {
"additionalHooks": "(useRecoilCallback|useRecoilTransaction_UNSTABLE)"
}
]
}
}
โ atom
โก๏ธatom ์ ์ธํ๊ธฐ
atom์ ์ํ์ ๋จ์๋ค. ์ ๋ฐ์ดํธ ์ ๊ตฌ๋ ์ด ๊ฐ๋ฅํ๋ฏ๋ก atom์ด ์ ๋ฐ์ดํธ๋๋ฉด ๊ตฌ๋ ๋ ๊ฐ ์ปดํฌ๋ํธ๊ฐ ์ ๊ฐ์ผ๋ก ๋ค์ ๋ ๋๋ง๋๋ค!
๋จผ์ atom์๋ key์ default ๊ฐ์ด ์กด์ฌํ๋ค. ๋จผ์ key๋ ๊ณ ์ ํ ์์ฑ์ผ๋ก, ๋๋ฒ๊น , ์ง์์ฑ, ๊ทธ๋ฆฌ๊ณ ๋ชจ๋ ์์์ ๋งต์ ๋ณผ ์ ์๋ ์ผ๋ถ ๊ณ ๊ธ API์ ์ฌ์ฉ๋๋ค.
default๋ React ์ปดํฌ๋ํธ์ state์ ๋น์ทํ ๊ธฐ๋ณธ๊ฐ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค.
1
2
3
4
const fontSizeState = atom({
key: "fontSizeState",
default: 14,
})
โก๏ธuseRecoilState()
์ปดํฌ๋ํธ์์ ์์์ ์ค์ ํ atom์ ์ฝ๊ฑฐ๋ ์ฌ์ฉํ๊ธฐ ์ํด์ useRecoilState
๋ผ๋ ํ
์ ์ฌ์ฉํ๋ค. React์ useState์ ๋น์ทํด์ ์ดํดํ๊ธฐ ์ฝ๋ค!
1
2
3
4
5
6
7
8
9
10
11
function FontButton() {
const [fontSize, setFontSize] = useRecoilState(fontSizeState) ๐
return (
<button
onClick={() => setFontSize((size) => size + 1)}
style=
>
Click to Enlarge
</button>
)
}
์ฒ์ recoil์ ์ฌ์ฉํด๋ณด๋ฉด์, ํน์ ์ปดํฌ๋ํธ์์ setFontSize
๋ฅผ ๋ฐ๋ก ์ฌ์ฉํด์ ์ํ๋ฅผ ์
๋ฐ์ดํธ ํด๋ ๋ค๋ฅธ ์ปดํฌ๋ํธ์ ๋์ผํ atom๊ฐ๋ ๋ณํ ๊น?๋ ๋ฌผ์์ด ์๊ฒผ๋ค.
(Redux์์๋ ๋ฐ๋ก ์ก์ ์ ์ ์ํ๊ณ , ์ก์ ์ ๋์คํจ์น ํ๊ณ ์ ๋ฐ์ดํธ ํ๊ธฐ ๋๋ฌธ์โฆ)
๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด ๊ฐ๋ฅํ๋ค! ๋๋ฌด ๊ฐํธํด์ ๋นํฉํ์ง๋ง, ์ ๋ง Recoil์ ์ด๋ ๊ฒ ์ํ๋ฅผ ์ ๋ฐ์ดํธ ํ ์ ์๋ค. ์ค๋ช ๊ทธ๋๋ก โreactโ์ค๋ฝ๊ฒ ๋ง์ด๋ค!
โ Selectors
selector์ atom์ด๋ ๋ค๋ฅธ selector์ ์ ๋ ฅ์ผ๋ก ๋ฐ๋ ์์ ํจ์๋ก, ์์ atom์ด๋ selector๊ฐ ์ ๋ฐ์ดํธ๋๋ฉด selectorํจ์๋ ๋ค์ ํ๊ฐ๋๋ค. ์ปดํฌ๋ํธ๋ atom๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก selector๋ฅผ ๊ตฌ๋ ํ ์ ์์ผ๋ฉฐ, selector์ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ๋ค์ ๋ ๋๋ง๋๋ค.
selector์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ํ์ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ฐํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. ์ด๋ฅผ ํตํด atom์ ์ต์ํ์ ์ํ๋ง ์ ์ฅ๋๊ณ , ๋๋จธ์ง๋ ๊ทธ ์ต์ํ์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํจ์จ์ ์ผ๋ก ๊ณ์ฐ๋๋ค.
selector์ get
๊ณผ ์ฌ์ฉ๋๋ค. get
์์ฑ์ ๊ณ์ฐ ๋ ํจ์๋ฅผ ๋ปํ๋ค! ์ด ํจ์๋ ์ ๋ฌ๋ get ์ธ์๋ฅผ ์ฌ์ฉํด atom ๋ฐ ๋ค๋ฅธ selector์ ๊ฐ์ ์ก์ธ์คํ ์ ์๋ค. ๋ค๋ฅธ atom์ด๋ selector์ ์ ๊ทผํด, ํด๋น atom์ด๋ selector๊ฐ ์
๋ฐ์ดํธ๋๋ฉด ์ด ํจ์๋ฅผ ๋ค์ ๊ณ์ฐํ๊ธฐ ์ํ ์ข
์์ฑ ๊ด๊ณ๊ฐ ์์ฑ๋๋ค.
1
2
3
4
5
6
7
8
9
const fontSizeLabelState = selector({
key: "fontSizeLabelState",
get: ({ get }) => {
const fontSize = get(fontSizeState)
const unit = "px"
return `${fontSize}${unit}`
},
})
์ด ์์ ์์๋ fontSizeState์ atom๊ฐ์ ๋ฐ์์ fontSize ๋ณ์์ ์ ์ฅํ๊ณ , 14px
๊ณผ ๊ฐ์ด px๊ฐ์ ๋ํ๋ด๋ ํน์ ๊ฐ์ ๋ง๋ค์ด return ํ๊ณ ์๋ค.
โก๏ธ์ฌ์ฉ์์
์ฌ์ค selector
์์ฒด๋ ๊ณต์๋ฌธ์๋ง ์ฝ๊ณ ์์ ํ ์ดํด๋ฅผ ๋ชปํ๋๋ฐ, ์ฌ์ฉํด๋ณด๋ฉด์ ๊ฐ์ ์ก์๋ค.
ํ์ฌ ์งํ์ค์ธ ํ๋ก์ ํธ๋ ๋ค๊ตญ์ด ๋ชจ๋๋ฅผ ์ง์ํ๋ ค๊ณ ํ๊ณ , Header์์ atom ์ํ(ko or jp ์ธ์ด)๋ฅผ ๊ต์ฒดํ ์ ์๋ค. ๊ทธ ๋ถ๋ถ์ด ํ๋จ์ language
๋ถ๋ถ์ด๋ค!
์ด๋ ์ ํ๋ language
์ ๋ฐ๋ผ ์ธ์ด๋ฐ์ดํฐ๊ฐ ๋ค์ด์๋ json ํ์ผ์ ์ฌ์ฉํด์ผ ํ๋๋ฐ, ์ด๋ selector๋ฅผ ์ฌ์ฉํด ๊ตฌํํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
"use client"
import { atom, selector } from "recoil"
import ko from "@/language/ko.json"
import jp from "@/language/jp.json"
export const language = atom<string>({
key: "nowLanguage",
default: "ko",
})
export const languageMode = selector({
key: "languageDataSelector",
get: ({ get }) => {
const nowLanguageMode = get(language)
return nowLanguageMode === "ko" ? ko : jp //์ธ์ด json ๋ฐ์ดํฐ ์ ํ
},
})
๐ฉ๋ง๋ฌด๋ฆฌ
์ด๋ ๊ฒ ๊ฐ๋จํ๊ฒ recoil์ ๋ํด ์์๋ดค๋ค! ํ์คํ redux๋ณด๋ค ํธํ๊ณ โreactโ์ค๋ฝ๋ค๋๊ฒ ์ด๋ค ์๋ฏธ์ธ์ง ์๋ฟ๋ ๊ฒ ๊ฐ๋ค.
์ฐธ๊ณ ๋ก recoil ๊ณต์๋ฌธ์๋ ํ๊ตญ์ด๋ฅผ ์ง์ํ๋ค! ์์ด, ํ๋์ค์ด, ํ๊ตญ์ด, ์ค๊ตญ์ด ์์ผ๋ก ์ ํ์ด ๊ฐ๋ฅํ๋ฐ, ํ๊ตญ์ด ๊ฐ๋ฐ์ ๋ถ๋ค์ด ๊ธฐ์ฌํ์ ๋ถ๋ถ์ผ๊น? (๋ง์ฝ ๊ทธ๋ ๋ค๋ฉด ์ ๋ง ๊ฐ์ฌํ๋ค)๐ฅบ
๋๋ ์ด๋ฐ ๊ธฐ์ฌ๋ฅผ ํด๋ณด๊ณ ์ถ๋ค๋ ์๊ฐ์ด ๋ ๋ค.๐