๋ฐ˜์‘ํ˜•


๐ŸŽฏ

Recoil์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


 

โœ… Recoil์ด๋ž€?

Recoil์€ React ํ”„๋กœ์ ํŠธ๋ฅผ ์œ„ํ•œ ๋งŽ์€ ์ „์—ญ ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ์ค‘ ํ•˜๋‚˜๋กœ, 2020๋…„ 5์›” Facebook์—์„œ ์ถœ์‹œํ•˜์˜€๋‹ค. ๊ทธ๋ ‡๊ธฐ์—, ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(Redux, Mobx)์™€๋Š” ๋‹ฌ๋ฆฌ React ์ „์šฉ์ด๋ฉฐ React์— ์ตœ์ ํ™”๋˜์–ด ์žˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Recoil์„ ์‚ฌ์šฉํ•˜๋ฉด atoms(๊ณต์œ  ์ƒํƒœ)์—์„œ selector(์ˆœ์ˆ˜ ํ•จ์ˆ˜)๋ฅผ ๊ฑฐ์ณ React component๋กœ ํ๋ฅด๋Š” data-flow graph๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ atoms๋Š” component๋ฅผ ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ์˜ ๋‹จ์œ„๊ณ  selector์€ ์ด ์ƒํƒœ๋ฅผ ๋™๊ธฐ์‹ ๋˜๋Š” ๋น„๋™๊ธฐ์‹์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

 

 

 

โœ… Recoil์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ  

 

recoil์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ „์—ญ ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ๋งŽ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋ช‡๊ฐ€์ง€ ๋‹จ์ ๋“ค์ด ์กด์žฌํ•˜์˜€๋‹ค.

 

  • React ์ „์šฉ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— React ๊ด€์ ์—์„  ์™ธ๋ถ€์š”์ธ์œผ๋กœ Store๊ฐ€ ์ทจ๊ธ‰๋˜๋ฉฐ, ๋™์‹œ์„ฑ ๋ชจ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ์— ํ˜ธํ™˜์„ฑ์ด ๋ถ€์กฑํ•˜๋‹ค.
  • Store, Action, Reducer ๋“ฑ ์‚ฌ์ „์— ์ค€๋น„ํ•ด์•ผํ•˜๋Š” ๋ณต์žกํ•œ Boiler Plate ์ดˆ๊ธฐ์„ธํŒ…์€ ๊ฒฐ๊ตญ ๋น„ํšจ์œจ์ ์ด๋ฉฐ ๋Ÿฌ๋‹์ปค๋ธŒ๊ฐ€ ๋†’๋‹ค.
  • Redux-saga ๋“ฑ ์ „์—ญ์ƒํƒœ์— ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•œ ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ฆ‰, ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ์— ์ถ”๊ฐ€ ๋ฆฌ์†Œ์Šค๊ฐ€ ์š”๊ตฌ๋œ๋‹ค๋‹ค.

์ด๋Ÿฌํ•œ ๋‹จ์ ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด recoil์ด ๋‚˜ํƒ€๋‚ฌ๊ณ  ๊ฐ€์žฅ ์ข‹์€ ์žฅ์ ์€ Boiler Plate ์–‘์ด ํ˜„์ €ํžˆ ์ ๋‹ค๋Š” ์ ์ด๋‹ค.

 

 

 

โœ… Recoil ์žฅ/๋‹จ์ 

๐ŸŸข Recoil ์žฅ์ 

  • ๋น„๋™๊ธฐ๋ฌธ์ œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๋™๊ธฐ์ƒํƒœ๋ฅผ ๋‹ค๋ฃจ๋“ฏ์ด ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ท€์ฐฎ์€ ๋น„๋™๊ธฐ์ƒํƒœ ์ฒ˜๋ฆฌ๋Š” Suspense์— ์œ„์ž„ํ•œ๋‹ค.
    • ์ฝ”๋“œ์˜ ๋ณต์žก๋„๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹จ์ˆœํ•˜๋‹ค
    • ๋ฆฌ๋•์Šค์˜ action, dispatch, reducer, store, ๋น„๋™๊ธฐ๋ฅผ ์œ„ํ•œ thunk, saga... ๋ณต์žกํ•˜๋‹ค 
    • ๋ฆฌ์ฝ”์ผ์€ atom, selector ๋‘๊ฐœ๊ฐ€ ์‚ฌ์‹ค์ƒ ๋์ด๋‹ค. ๋‹จ์ˆœํ•˜๋‹ค 
    • ๊ณผ์—ฐ ๋ฆฌ๋•์Šค ์ดˆ์‹ฌ์ž์—๊ฒŒ ๋ฆฌ๋•์Šค๋ฅผ ์†Œ๊ฐœํ• ๋•Œ๋„ ์ด ๊ธ€์ฒ˜๋Ÿผ ์งง๊ฒŒ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์„๊นŒ? 
  • ๋ฆฌ์•กํŠธ์™€ ๊ฐœ๋ฐœ ๋ฐฉํ–ฅ์„ฑ์ด ๊ฐ™๋‹ค
    • 2๋…„๋ฐ˜ ์ „์— ๋“ฑ์žฅํ•œ ๋ฆฌ์•กํŠธ์˜ hooks๊ฐ€ ์ฒ˜์Œ ๋‚˜์™”์„๋•Œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ผ
    • ์ฒ˜์Œ์—๋Š” Class๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ์— ์ต์ˆ™ํ•ด์„œ ๊ฑฐ๋ถ€๊ฐ์ด ์žˆ์—ˆ๋‹ค.
    • ํ•˜์ง€๋งŒ hooks๊ฐ€ ์„ ์–ธ์ ์ธ API๋กœ ์ฝ”๋“œ๋ฅผ ์–ผ๋งˆ๋‚˜ ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฐ”๊ฟ”์ฃผ์—ˆ๋Š”์ง€ ์ƒ๊ฐํ•ด๋ณด๋ผ
    • recoil์€ ๋˜ํ•œ๋ฒˆ ์„ ์–ธ์ ์ธ API๋กœ ์ฝ”๋“œ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฐ”๊พธ๋ ค ํ•˜๊ณ ์žˆ๋‹ค.
    • ์‚ฌ์‹ค ์ฝ”๋“œ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฐ”๊พธ๋Š”๊ฒƒ ์ด์ƒ์˜ ์˜์˜๊ฐ€ ์žˆ๋‹ค.
  • ์„ ์–ธ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ
    • ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ JSX๋กœ ์„ ์–ธํ•จ์œผ๋กœ์จ ๋ชจ๋“  ๋น„๋™๊ธฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.
  • ๋‚ด์šฉ์ด ๊ธธ์–ด์ ธ ๊ธ€์— ๋‹ด์ง€ ๋ชปํ•œ ์žฅ์ ๋“ค
    • ์บ์‹ฑ๊ธฐ๋Šฅ์œผ๋กœ ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ๋น ๋ฅด๊ฒŒ ํ•จ
    • ์ƒํƒœ๋ฅผ ๋ถ„์‚ฐ์ ์œผ๋กœ ๋‘˜ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ ์Šคํ”Œ๋ฆฌํŒ…์ด ๊ฐ€๋Šฅํ•จ

๐Ÿ”ด Recoil ๋‹จ์ 

  • ์•ˆ์ •์„ฑ์— ๋Œ€ํ•œ ๊ฑฑ์ •
    • ๋ ˆํฌ์ง€ํ† ๋ฆฌ๊ฐ€ facebook/Recoil์ด ์•„๋‹ˆ๊ณ  facebookexperimental/Recoil์ด๋‹ค.
  • ์‹คํ—˜์ ์ธ API๋“ค
    • recoil์˜ api์ค‘์—๋Š” ์•„์ง๋„ _UNSAFE surfix๊ฐ€ ๋ถ™์€๊ฒƒ์ด ๋งŽ๋‹ค
    • ํ•˜์ง€๋งŒ ๋น ๋ฅธ ์†๋„๋กœ UNSAFE ๋”ฑ์ง€๊ฐ€ ๋–ผ์ง€๊ณ  ์žˆ๋‹ค.
  • devtools์˜ ๋ถ€์žฌ
    • ๋ฆฌ๋•์Šค์˜ devtools ๋งŒํผ ํ›Œ๋ฅญํ•œ ๋””๋ฒ„๊น…ํˆด์ด ์•„์ง ์—†๋‹ค.
    • ๋น„๊ณต์‹ devtools ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์žˆ๊ธฐ๋Š” ํ•œ๋ฐ ํ€„๋ฆฌํ‹ฐ๊ฐ€ ์ข‹์ง€๋Š” ์•Š๋‹ค
  • ๊ด€๋ จ ์˜คํ”ˆ์†Œ์Šค ์ƒํƒœ๊ณ„๊ฐ€ redux์— ๋น„ํ•ด์„œ ๋ถ€์กฑํ•˜๋‹ค
    • ์•„๋ฌด๋ž˜๋„ redux๊ฐ€ ์˜ค๋ž˜๋˜๊ณ  ์‚ฌ์šฉ๊ธฐ์—…์ด ๋งŽ๋‹ค๋ณด๋‹ˆ ๊ด€๋ จ ์˜คํ”ˆ์†Œ์Šค๊ฐ€ ํ™œ๋ฐœํ•˜๋‹ค
    • localStorage์™€ ์—ฐ๋™ํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์œ ์ง€์‹œํ‚ค๋Š” persist ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ณด์ž
    • redux-persist โญ๏ธ 12K
    • recoil-persist โญ๏ธ 213
      • ๊ธฐ๋Šฅ์ด ์ข€ ๋”ธ๋ฆฐ๋‹ค. migration์ด ์—†๋‹ค

 

 

โœ… Recoil ์˜ˆ์ œ๋ฅผ ๋งŒ๋“ค๊ธฐ ์•ž์„œ

โœ” RecoilRoot 

๋ฆฌ์ฝ”์ผ state๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์€ <RecoilRoot>๋ฅผ ํ•„์š”๋กœ ํ•œ๋‹ค.  <RecoilRoot>๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€๊ณณ์€ root component์ด๋‹ค.

 

import { RecoilRoot } from "recoil";
import Counter from "./Counter";

function App() {
  return (
    <RecoilRoot>
      <Counter />
    </RecoilRoot>
  );
}

export default App;

 

โœ” Atom

์•„ํ†ฐ์€ ์ƒํƒœ๋ฅผ ๋งํ•˜๋ฉฐ ์–ด๋– ํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ ์”Œ์—ฌ์ง€๊ณ  ์ฝํ˜€์งˆ ์ˆ˜ ์žˆ๋‹ค. ์•„ํ†ฐ์˜ ๋ฐธ๋ฅ˜๋ฅผ ์ฝ๋Š” ์ปดํฌ๋„ŒํŠธ๋“ค์€ ์•”๋ฌต์ ์œผ๋กœ ๊ทธ ์•„ํ†ฐ์—๊ฒŒ subscribe๋˜์–ด์ง€๊ณ  ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„ํ†ฐ์˜ ์—…๋ฐ์ดํŠธ๋Š” ์ด ์•„ํ†ฐ์„ ์ฐธ๊ณ ํ•˜๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ re-render์‹œํ‚จ๋‹ค.

 

import { atom } from "recoil";

let countState = atom({
  key: "counter",
  default: 0,
});

export default countState;

 

โœ” Selector

Recoil์€ selector API๋ฅผ ์ œ๊ณตํ•œ๋‹ค. React์˜ useMemo, Redux์˜ selector ์ฒ˜๋Ÿผ ๋‹ค๋ฅธ ์ƒํƒœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํŒŒ์ƒ๋œ ์ƒํƒœ(derived state) ๋งŒ๋“ค์–ด๋‚ด๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ์ž‘์—… ๋ชฉ๋ก์—์„œ ์™„๋ฃŒ๋œ ์ž‘์—…๋งŒ ํ•„ํ„ฐ๋ง ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

(์ด๋ฒˆ ์˜ˆ์ œ์—์„œ๋Š” recoil์„ ๊ฐ€์žฅ ๊ฐ„๋‹จํžˆ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์ƒ๋žตํ•œ๋‹ค.)

 

โœ” useRecoilState

useState์™€ ๊ฐ™์€ ์—ญํ• ์ด๋ผ๊ณ  ๋ด๋„ ๋ ๊ฑฐ ๊ฐ™๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ ํŒŒ์ผ์— ์žˆ๋Š” ์•„ํ†ฐ์„ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์—์„œ useSelector์™€ ๋น„์Šทํ•œ๊ฑฐ ๊ฐ™๊ธฐ๋„ ํ•˜๋‹ค.

๋‹ค์‹œ ๋งํ•ด์„œ, ์•„ํ†ฐ์˜ ์ƒํƒœ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ๋ณ€๊ฒฝ ์‹œํ‚ฌ ์ˆ˜ ๋„ ์žˆ๋‹ค.

 

โœ” useRecoilValue

์•„ํ†ฐ์„ ์กฐํšŒํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

 

โœ” useSetRecoilState

setter ์—ญํ• ์„ ํ•œ๋‹ค. useSetRecoilState๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•„ํ†ฐ์„ ๋ณ€๊ฒฝ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

 

โœ” useResetRecoilState

์•„ํ†ฐ ๊ฐ’์„ ๋””ํดํŠธ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝ์‹œ์ผœ์ค€๋‹ค.

 

 

 

โœ… Recoil ์˜ˆ์ œ

Recoil์„ ์ด์šฉํ•˜์—ฌ counter์„ ๋งŒ๋“ค์–ด ๋ณด๊ณ ์ž ํ•œ๋‹ค.

 

 

[App.js]

Recoil์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” RecoilRoot๋ฅผ ๊ฐ์‹ธ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

import { RecoilRoot } from "recoil";
import Counter from "./Counter";

function App() {
  return (
    <RecoilRoot>
      <Counter />
    </RecoilRoot>
  );
}

export default App;

 

[Atom.js]

Recoil์„ ํ†ตํ•ด ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ atom์„ ๋งŒ๋“ค์–ด์ค€๋‹ค. ์ด๋•Œ countState๋Š” deafult๊ฐ€ 0์ธ atom์ด๋‹ค.

import { atom } from "recoil";

let countState = atom({
  key: "counter",
  default: 0,
});

export default countState;

 

 

[Counter.js]

 

Counter๋ฅผ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ์ด๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” recoil์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ(get) ์œ„ํ•ด useRecoilValue ๋ฅผ ์‚ฌ์šฉํ•˜์˜€๊ณ 
๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๊ธฐ(set) ์œ„ํ•ด์„œ๋Š” useSetRecoilState ๋ฅผ ์‚ฌ์šฉ
default๊ฐ’์œผ๋กœ ๋ฆฌ์…‹ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” useResetRecoilState ๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

import { useRecoilValue, useResetRecoilState, useSetRecoilState } from "recoil";
import countState from "./Atom";

function Counter() {
  const count = useRecoilValue(countState); // useRecoilValue : get only
  const handleCount = useSetRecoilState(countState); // useSetRecoilState : set only
  const handleResetCount = useResetRecoilState(countState); // useResetRecoilState : reset default

  const handlePlus = () => {
    handleCount((count) => count + 1);
  };
  const handleMinus = () => {
    handleCount((count) => count - 1);
  };
  const handleReset = () => {
    handleResetCount();
  };
  return (
    <div>
      <h2>Recoil Counter</h2>
      <div>{count}</div>
      <button onClick={handlePlus}>+</button>
      <button onClick={handleMinus}>-</button>
      <button onClick={handleReset}>reset</button>
    </div>
  );
}

export default Counter;

 

 

 

 

https://abangpa1ace.tistory.com/212

https://velog.io/@gomjellie/3%EB%B6%84-Recoil#recoil-%EB%8B%A8%EC%A0%90

๋ฐ˜์‘ํ˜•