Recoil Basic
recoil ๊ด๋ จ reference
๋ชฐ์ ์ฝ๋ฉ ์์นด์ด๋ธ - recoil
์ฝ์ผ์๋น
https://kitemaker.co/blog/lessons-learned-from-moving-to-recoil
react-query
๋ ์๋ฒ ์ํ๋ฅผ ๋ค๋ฃจ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌredux
,mobx
๋ฑ์ ํด๋ผ์ด์ธํธ ์ํ๋ฅผ ๋ค๋ฃจ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
recoil ์ฐธ๊ณ ๊ธ -https://medium.com/humanscape-tech/recoil-์์๋ณด๊ธฐ-285b29135d8e
https://abangpa1ace.tistory.com/212 - atomFamily(), selectorFamily()
https://youtu.be/JvWukLAdS_8 - recoil tutorial
https://recoiljs.org/ko/docs/guides/asynchronous-data-queries/ - recoil ๋น๋๊ธฐ ์ฒ๋ฆฌ
https://blog.woolta.com/categories/1/posts/209
https://taegon.kim/archives/10125
https://www.youtube.com/watch?v=JvWukLAdS_8 - recoil ๋์์ ์ค๋ช
https://www.youtube.com/watch?v=-_IzPd_bFNk - recoil ๋์์ ์ค๋ช
selectorFamily - ํ๋ผ๋ฏธํฐ ๊ฐ์ ๋๊ธธ๋
https://velog.io/@juno7803/Recoil-Recoil-200-ํ์ฉํ๊ธฐ ์ ๋ฆฌํ ๊ธ์
๋๋ค.
useRecoilState()
์ญํ ์ ๋ฐ์ผ๋ก ์ชผ๊ฐ๋ฉด
useRecoilValue()
value๋ง ํ์ํ ์ปดํฌ๋ํธuseSetRecoilState()
state๋ฅผ ๋ณ๊ฒฝํ๊ธฐ๋ง ํ๋ ์ปดํฌ๋ํธ
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { cookieState } from '../../state';
const cookies = useRecoilValue(cookieState);
const setCookies = useSetRecoilState(cookieState);
useResetRecoilState()
์ธ์๋ก ๋ฐ์์จ atom์ state๋ฅผ default ๊ฐ์ผ๋ก reset ์ํค๋ ์ญํ
const resetCookies = useResetRecoilState(cookieState);
selectorํจ์:
selector๊ฐ atom์ ๊ตฌ๋ ํ๊ณ ์๋ค๊ฐ ์ด๋ฏธ ์ ์ธ๋ atom์ด ๊ฐ์ด ๋ณํ ๋, ๋ค์ ์คํ๋จ(atom ๊ตฌ๋ ๊ธฐ๋ฅ)
์๋ฒ์ ํต์ ํ๋ ๋น๋๊ธฐ ๊ฐ(response.data)์ ์์ ์ ๊ฐ์ผ๋ก ๊ฐ์ง ์ ์์
function selector<T>({
key: string,
get: ({
get: GetRecoilValue
}) => T | Promise<T> | RecoilValue<T>,
set?: (
{
get: GetRecoilValue,
set: SetRecoilState,
reset: ResetRecoilState,
},
newValue: T | DefaultValue,
) => void,
dangerouslyAllowMutability?: boolean,
})
selector๋ read-only ํ
RecoilValueReadOnly
๊ฐ์ฒด๋ก์ return ๊ฐ ๋ง์ ๊ฐ์ง ์ ์๊ณ ๊ฐ์ set
ํ ์ ์๋ ํน์ง
state.js
export const cookieState = atom({
key: 'cookieState',
default: []
});
export const getCookieSelector = selector({
key: "cookie/get",
get: async ({ get }) => {
try{
const { data } = await client.get('/cookies');
return data.data;
} catch (err) {
throw err;
}
},
set: ({set}, newValue)=> {
set(cookieState, newValue)
}
});
key: selector๋ฅผ ๊ตฌ๋ถํ ์ ์๋ ์ ์ผํ
id
, ์ฆ key ๊ฐ์ ์๋ฏธget: ์๋
derived state
๋ฅผ return ํ๋ ๊ณณ. ์์ ์ฝ๋์์๋ api call์ ํตํด ๋ฐ์์จ data๋ฅผ return,๊ตฌ๋ ํ๊ณ ์๋ atom์ ๊ฐ์ด setState์ ์ํด ์์ ๋์ ๋, get์ ํ ๋น๋ ํจ์๊ฐ ์ฌ์คํ๋จ.
const cookie = useRecoilValue(selector)
์ด๋ ๊ฒ ์กฐํ ๊ฐ๋ฅset: writeable ํ state ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ํจ์๋ฅผ return ํ๋ ๊ณณ
selector๋ read-only ํ return ๊ฐ(
RecoilValue
)๋ง ๊ฐ์ง๊ธฐ ๋๋ฌธ์ set์ผ๋ก๋ writeableํ atom ์RecoilState
๋ง ์ค์ ๊ฐ๋ฅ
set: ({set}, newValue) => { set(getCookieSelector, newValue) } // incorrect : cannot allign itself
set: ({set}, newValue) => { set(cookieState, newValue) } // correct : can allign another upstream atom that is writeable RecoilState
const [cookie, setCookie] = useRecoilState(cookieState);
Suspense, ๋น๋๊ธฐ ์ํ ์ฒ๋ฆฌ
import React,{ Suspense } from 'react';
import { Cookies } from '../components';
const App = () => {
return(
<RootRecoil>
<Suspense fallback={<div>Loading...</div>}> // shimmer ์ฃผ์
๊ฐ๋ฅ
<Cookies />
</Suspense>
</RootRecoil>
);
}
export default App;
Suspense๋์ Recoil์ Loadable์ ์ฌ์ฉํ ์๋ ์๋ค
import { getCookieSeletor } from '../../reocil';
import { useRecoilState, useRecoilValueLoadable } from 'recoil';
const Cookies = () => {
const cookieLoadable = useRecoilValueLoadable(getCookieSelector);
switch(cookieLoadable.state){
case 'hasValue':
return (
<>
(<div>
{cookieLoadable.contents.map(cookie =>(
<Card
cookies={cookie}
key={cookie.id}
idx={cookie.id}
/>
))}
</div>)
</>
});
case 'loading':
return <Loading />;
case 'hasError':
throw cookieLoadable.contents;
}
export default Cookies;
Loadable ๊ฐ์ฒด
const cookieLoadable = useRecoilValueLoadable(getcookieSelector);
state : hasValue
, hasError
, loading
atom ์ด๋ selector์ ์ํ๋ฅผ ๋งํ๋ฉฐ, ์์ ์ธ ๊ฐ์ง ์ํ
contents: atom์ด๋ contents์ ๊ฐ์ ๋ํ๋ด๋ฉฐ, ์ํ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฐ ๋ณด์ .
hasValue
์ํ์ผ ๋value
hasError
์ผ ๋Error
๊ฐ์ฒดloading
์ผ ๋Promise
selector๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฐ์ ์บ์ฑ
๊ธฐ์กด์ atom์ ์ด์ฉํ ๋ฐฉ์์ ๋งค๋ฒ api call์ ํ๊ณ ์๋ ๋ฐ๋ฉด, selector๋ก ๋ฐ๊ฟ์ ๊ตฌํํ์ ๋, ํ๋ฒ call์ ํ๋ api์ ๋ํ ์บ์ฑ์ด ์ด๋ฃจ์ด์ ธ ๋ค์ ํธ์ถํ์ง ์์
์บ์(cache)๋ ์ปดํจํฐ ๊ณผํ์์ ๋ฐ์ดํฐ๋ ๊ฐ์ ๋ฏธ๋ฆฌ ๋ณต์ฌํด ๋๋ ์์ ์ฅ์๋ฅผ ๊ฐ๋ฆฌํจ๋ค. ์บ์๋ ์บ์์ ์ ๊ทผ ์๊ฐ์ ๋นํด ์๋ ๋ฐ์ดํฐ๋ฅผ ์ ๊ทผํ๋ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ๊ฒฝ์ฐ๋ ๊ฐ์ ๋ค์ ๊ณ์ฐํ๋ ์๊ฐ์ ์ ์ฝํ๊ณ ์ถ์ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋ค. ์บ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๋ณต์ฌํด ๋์ผ๋ฉด ๊ณ์ฐ์ด๋ ์ ๊ทผ ์๊ฐ ์์ด ๋ ๋น ๋ฅธ ์๋๋ก ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์๋ค
atomFamily
์ด Family ๋ฉ์๋๋ค์ atom(ํน์ selector)์ ๋ฆฌํดํ๋ ํฉํ ๋ฆฌ ํจ์์ด๋ค. ์ธ์(params)๋ฅผ ๋ฐ์, ์ด๋ฅผ ๋ฐ์ํ ๋์ ์ธ ์ํ๊ฐ์ ๋ฐํํ๋ค.
๊ทธ๋ ๊ธฐ์, Recoil ๋ด ๋ค๋ฅธ ์ํ๊ฐ์ด ์๋, ์ธ๋ถ์ธ์(Query Params ๋ฑ)๋ฅผ ํ์ฉํ ์ํ๊ฐ์ ๊ด๋ฆฌํ๊ธฐ์ ์ ๋ฆฌํ๋ค.
์ธ๋ถ์์ ํ๋ผ๋ฏธํฐ๋ก ๊ฐ์ ๋ฐ์์์ selector์ ์ ์ฉํด์ผ ํ ๊ฒฝ์ฐ์ selectorFamily
selectorFamily
ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ํ ๋น๋๊ธฐ ๋ฐ์ดํฐ : selectorFamily()
selector
์ selectorFamily
๋ ๋ฐฉ์์ ์ฐจ์ด๋ ํ๋ผ๋ฏธํฐ์ ์ ๋ฌด
๊ตณ์ด ์ํ์ ์ ์ฅํ ํ์๊ฐ ์๋ ๊ฐ์ด๋ผ๋ฉด selectorFamily
๋ฅผ ์ฌ์ฉ
`https://baseUrl.com/type=${apiTypes}`
// state.jsx
export const githubRepo = selectorFamily({
key: "github/get",
get: (githubId) => async () => {
if (!githubId) return "";
const { data } = await axios.get(
`https://api.github.com/repos/${githubId}`
);
return data;
},
});
// Github.jsx
import { useRecoilValue } from 'recoil';
import { selectorFamily } from '../../state';
const Github = () => {
const githubId = 'juno7803';
const githubRepos = useRecoilValue(githubRepo(githubId));
return(
<>
<div>Repos : {githubRepos}</div>
</>
)
}
export default Github;
Last updated