ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React / Recoil 의 기초 개념과 기본 동작을 쉽게 설명해봤다( Atoms, Selector)
    DEV/REACTJS 2022. 8. 15. 16:23
    728x90
    반응형


    Recoil

    Recoil의 사전적 의미는 '반동' 이라는 뜻인데 이 라이브러리와 어떤 관련이 있을까.

    Recoil은 전역으로 상태를 관리할 수 있는 '페이스북'에서 만든 라이브러리다!

    여기서 벌써 두 개의 문제가 나온다.

     

    전역 >

    간단히 말해 내가 만드는 app 전체의 공간을 의미한다고 이해하면 쉽다.

     

    상태 >

    간단히 말해 변수, 그리고 변수를 바꿀수 있는 함수들(set)을 의미한다고 이해하면 쉽다.

     

    기존 Redux, MobX를 써본 경험은 없지만, 이것들과 굉장히 유사하다던데 전자로 말한 라이브러리들은

    전역 상태관리가 아닌, 엄연히 말하자면 외부요인으로 내부를 변경시키는 그러한 개념인것 같다.

     

    Recoil은 내부에서 React의 관리가 가능한데, 바로 떠올릴 수 있는것이 useContext와 어떤 차이가 있냐! 일수 있다.

    useContext와 Recoil의 차이점

    useContext도 전역적인 상태를 관리하지만, 어떻게 보면 가장 상위의 root에서 프롭 드롤링을 통해 하위에 데이터를 전달해주는,

    즉 그냥 프롭스 넘기는거랑 다를게 없는 느낌이 든다.

    하지만 Recoil은 진짜 변하는 것만 감지해서, 전역에서 데이터를 참고해서 변경해주니, 놀라운 녀석이다.

     

    Recoil의 주요 기능

    1.유연한 상태 관리

    • 보일러 플레이트 없음
    • get set 만큼 쉬움
    • 코드 분할을 허용

    2.데이터 추출

    • 다른 추출 데이터로부터 안전하고 간편하게 데이터 사용 가능
    • 이미 접근한 상태에 똑같은 방법으로 데이터 추출이 가능
    • 동기 비동기로 데이터 접근 가능

    3. app wide state observation

    • read any part of recoil state
    • observe changes to state
    • persist application state
    • rehydration (backwards compatible)

    Recoil을 사용한 예제

    예제는 공식 문서에서 추천해주는 가이드 영상을 보고 따라 만들어 봤음!

     

    설치

    우선 리코일을 사용하기 위해선, 리코일을 사용할 app에 리코일을 설치해야한다

    npm install recoil / yarn install recoil

    npm이든 yarn이든 상관없음!

     

    사용

    Recoil은 생각보다 방대한데, 아주 기초적인 개념만 설명해보고자 한다.

     

    우선 리코일을 통해 상태를 관리하고자 한다면, 상태관리가 될 녀석들을

    RecoilRoot를 불러준 후 통해 묶어준다.

    그리고 이제부터 본격적인 Recoil 사용이 가능해진다.

     

    Atoms

    먼저 사용해볼 것은 Atom이라는 것이다.

    Atoms은 간단히 말해 React에서 state라고 생각하면 된다.

     

    Atoms을 사용하기 위해서는 atom을 정의해줘야한다.

    import {atom,useRecoilState, useRecoilValue } from 'recoil'
    
    const darkModeState = atom({
      key:'darkMode',
      default:false,
    })

    아톰에는 객체로 두가지 요소를 넣는데,

     

    첫번째는 key값이다. key값은 고유해야하고, 이 키값들을 통해 Recoil이 적용되는 컴포넌트 들에서

    useReocilState, useRecoilValue와 같은 메서드를 통해 해당하는 atom(state)를 불러올 수 있도록

    도와주는 친구다

     

    두번째는 default값이다. 말 그대로 default로 사용될 값을 의미하며 useState('here!')에서 'here!' 부분과

    비슷하다고 생각하면 된다!

     

    내가 본 강의에서는 darkmode를 만들어보는 예제였기 때문에 기본 값을 false로 지정해줬다.

     

    지정해준 값들을 이제 불러와서 사용해볼것이다.

     

     

    const DarkModeSwitch = () => {
    
      const [darkMode, setDarkMode] = useRecoilState(darkModeState);
    
    
      return <input 
                type="checkbox"
                checked={darkMode}
                onChange={(event) => {
                  setDarkMode(event.currentTarget.checked)
                }}
              />
    }

    위는 DarkMode를 켜고 끄는 스위치를 return 하는 함수다.

    중요하게 여겨봐야할 부분은 useRecoilState() 부분이다.

    마치 useState()와 그냥 동일하다.

    다만 useState에는 인수로 초기값을 넣어주는데 반해, useRecoilState에는 Atom의 key값을 넣어준다.

    그리고 구조 분해를 통해 useState처럼 var, setVawr 형태로 리턴값을 받아온다.

     

    그렇게 되면 우리가 아는 setState마냥 사용해주면된다.

     

    const Button = () => {
    
      const darkMode = useRecoilValue(darkModeState);
    
      return <button style={{
      backgroundColor: darkMode ? 'black' : 'white',
      color: darkMode ? 'white' : 'black'}}>My UI Button</button>
    }

    아래는 위에서 정의해준 darkMode의 ui 부분이다.

     

    내용을 보면 뭔가를 받아왔는데 이번에는 useRecoilValue로 해당 값을 받아왔다.

    이렇게 되면 해당 키값의 atom에 저장되어있는 value값만 가져오게 되는 것이다.

    이 값을 그냥 이용만 해주면된다.

    결과물

    짱편함!

     

    Selector

    다음 사용해볼 것은 Selector

    나는 처음에 여기서 개념이 꼬여서 약간 헷갈렸는데,

    간단히 말하자면 get과 set을 정의할 수 있는 그런 녀석

     

    여기서 내가 생각하는 get과 set의 의미를 정햊봄

     

    get >

    어떠한 값을 가져올 수 있음.

    그 값은 다른데 할당해도 괜찮고 맘대로 사용할 수 있음.

    한번에하나의 값만 가져오는게 아닌 여러개의 값들을 가져올 수 있으며,

    분기를 통해 원하는 상태일때 원하는 값을 가져올수 있음

    그리고 return 을 통해 원하는 값을 반환함

     

    set >

    어떠한 값을 변경 혹은 재 설정할 수 있음.

    다른 언어에서도 있겠지만, 특히 리코일에서는 set(Atom이 할당된 변수, 넣을 값)의 형태로 값을 바꿀 수 있음

    return이 따로 없어도 됨

    set과 get을 한꺼번에 불러올 수 있음

     

    사용을 할때는 상태값을 변경하는 것이니 useRecoilState를 불러오며 인수로는

    정의를 한 selector의 변수를 넘긴다. 가 기본인데

    일단 아래는 전체 코드와 예제 웹임

     

    const usdAtom = atom({
      key:'usd',
      default:1,
    })
    
    const eurSelector = selector<number>({
      key:"eur",
      get: ({get}) => {
        let usd = get(usdAtom);
    
        const commissionEnabled = get(commissionEnabledAtom)
        if(commissionEnabled){
          const commission = get(commissionAtom)
          usd = removeCommission(usd,commission)
        }
    
        return usd * exchangeRate
      },
      set:({set,get},newEurValue) => {
    
        //@ts-ignore
        let newUsdValue = newEurValue / exchangeRate
    
        const commissionEnabled = get(commissionEnabledAtom)
        if(commissionEnabled){
          const commission = get(commissionAtom)
          newUsdValue = addCommission(newUsdValue,commission)
        }
    
        set(usdAtom,newUsdValue)
      },
    })
    
    export const Selectors = () => {
      
      const [usd, setUSD] = useRecoilState(usdAtom);
      const [eur,setEUR] = useRecoilState(eurSelector)
    
      return (
          <div style={{padding: 20}}>
              <Heading size="lg" mb={2}>
                  Currency converter
              </Heading>
              <InputStack>
                  <CurrencyInput label="usd" amount={usd} onChange={(usd) => setUSD(usd)} />
                  <CurrencyInput label="eur" amount={eur} onChange={(eur) => setEUR(eur)}/>
              </InputStack>
              <Commission />
          </div>
      )
    }
    
    ...
    
    const commissionEnabledAtom = atom({
      key: 'commissionEnabled',
      default: false,
    })
    
    const commissionAtom = atom({
      key: 'commission',
      default: 5,
    })
    
    const Commission = () => {
      const [enabled, setEnabled] = useRecoilState(commissionEnabledAtom)
      const [commission, setCommission] = useRecoilState(commissionAtom)
     
     ...
     
      const addCommission = (amount: number, commission: number) => {
      return amount / (1 - commission / 100)
    }
    
    const removeCommission = (amount: number, commission: number) => {
      return amount * (1 - commission / 100)
    }

    위는 전체 코드는 아니고 이 글을 읽기 위해 필요한 부분만 따온 내용임

     

    위의 예제

    해당 프로젝트는 값 받으면 변환시키는 것으로, 양방향 변환이 가능한 환전기임.

    만약 commission이 있다면 해당 값을 반영해 돈을 계산해줌

     

    코드를 위에서 부터 설명해보자면

     

    1. useAtom에 atom 매서드를 활용해 key값과 default value 값을 정함

    2. Selectors라는 메인 함수에서 usd와 setUsd값을 useRecoilState를 통해 받아옴

    3. usd -> eur은 편하게 되는데 역으로 진행하려면, eur 부분에도 똑같은 로직을 진행해줘야함.

    4. 하지만 eur은 추가적으로 usd를 기준으로 커미션에 의한 변경이 있기 때문에, 조금 더 굉장한 함수가 되어야함

    5. 그래서 selector을 사용해줌

     

    그리고 여기서 부터는 새로운 부분이니 코드를 활용해서 설명을 주겠음.

     

    const eurSelector = selector<number>({
      key:"eur",
      get: ({get}) => {
        let usd = get(usdAtom);
    
        const commissionEnabled = get(commissionEnabledAtom)
        if(commissionEnabled){
          const commission = get(commissionAtom)
          usd = removeCommission(usd,commission)
        }
    
        return usd * exchangeRate
      },
      set:({set,get},newEurValue) => {
    
        //@ts-ignore
        let newUsdValue = newEurValue / exchangeRate
    
        const commissionEnabled = get(commissionEnabledAtom)
        if(commissionEnabled){
          const commission = get(commissionAtom)
          newUsdValue = addCommission(newUsdValue,commission)
        }
    
        set(usdAtom,newUsdValue)
      },
    })

    우선 recoil에서 selector을 불러서 저장을 해둠

    selector도 atom과 똑같이 고유한 키를 저장해야함.

    그리고 다른점은 get과 set을 정의할 수 있다는 것임.

     

    get에서는 get객체를 받아와서 get을 이용할 수 있는데

    받아온 get에는 참조할 atom을 넣어줌

     

    그리고 원하 값으로 로직을 진행한 다음 return으로 get을 요청했을때 반환할 값을 넣어주면 끝!

     

    set에서는 set, get을 한꺼번에 객체로 불러올 수 있고, set함수를 부를때 전달하려고 한 인자값을 파라미터로 받음

     

    나머지는 get과 비슷한데

    마지막에 set을 통해 (해당하는 Atom에, 내가 넣고싶은 값)을 넣어주면 됨

     


    이렇게 atom과 selector의 설명을 마무리 해보갔음

    나도 아직 실무에 써본적은 없음 그래서 어떻게 쓸지 머리상상으로만 하고있고

    지금 강의 이외에도 고급 내용이 많기 때문에 내용을 들을 때마다 해당 내용을 최대한! 알기쉽게! 적어서 풀어보려고함

     

    이상!

     


    참고링크

     

    GitHub - curomame/Recoil_study: Recoil의 공식 문서 내용과 공식 문서에서 추천해준 영상을 보며 공부하는

    Recoil의 공식 문서 내용과 공식 문서에서 추천해준 영상을 보며 공부하는 Recoil. Contribute to curomame/Recoil_study development by creating an account on GitHub.

    github.com

     

     

    Learn Recoil - Free Recoil.js course

     

    learnrecoil.com

     

    반응형

    댓글

Designed by Tistory.