ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [상태관리, Recoil] Recoil을 사용해보자!
    Front-end/State management 2022. 4. 8. 18:46

    안녕하세요! 오늘은 상태관리를 위한 패키지 중 하나인 "Recoil"에 대해 알아보도록 하겠습니다!

    상태관리를 위한 패키지 중에는 많은 것들이 있는데요. 대표적으로 "Redux"가 있죠! 👏🏻 저는 개인적으로 리덕스의 작동 방식이 너무 복잡하다고 느껴서 Recoil을 상태관리에 이용해볼려고 하고 있습니다!

     

    물론, 대형 프로젝트에서 Redux는 그 힘을 충분히 발휘할 수 있겠지만, 소규모 프로젝트와 토이 프로젝트를 할 때에는 오히려 걸리적거리더라고요! 하지만 Recoil은 react hooks와 비슷한 재질(?) 이라는 느낌이 들어서 사용하는데 어색하지도 않고 직관적이라 개인적으로 좋은 것 같습니다!

     

    저는 recoil을 연습하기 위해, 다크모드가 있는 간단한 투두 앱을 구현해보았습니다 😀

     

     

    https://624ff6390c2a5c0009b987ef--lustrous-cheesecake-2c88b8.netlify.app/
    궁금하신 분들은 요기로.. 총총

     

    Recoil을 사용하며 배운 것들을 정리해보도록 하겠습니다. 👋🏻

     

    우선 Recoil을 다운로드 받도록 해야겠죠!

    npm install recoil

     

    RecoilRoot

    다운로드를 받았으면 우리는 recoil을 사용하기 위한 컴포넌트에 recoilroot를 씌워주어야 합니다.

    아! react 버전이 업되면서 root.render의 선언 방식이 달라졌답니다. 하하

    저렇게 RecoilRoot를 씌워주었다면 recoil을 사용할 수 있게 됩니다.

     

    Atom

    아톰은 상태의 일부를 나타냅니다. 저는 atom.tsx라는 파일을 따로 만들어 상태들만 모아놓는데요. 아톰의 형태는 이렇습니다.

    const textState = atom({
      key: 'textState', // unique ID (with respect to other atoms/selectors)
      default: '', // default value (aka initial value)
    });

    atom은 key와 default를 가지는데요, useState와 굉장히 비슷하지 않나요? 저는 그렇게 생각이 들어서 다루기에 무척 편하더라고요!

    이렇게 state를 저장하는 atom을 만들 수 있습니다!

     

    그렇다면 이 atom을 어떻게 사용할 수 있을까요?

     

    useState와 마찬가지로 우리는 set을 위한 atom관리 함수와 value를 위한 atom관리 함수를 사용할 수 있습니다.

     

    useRecoilValue

    우리가 darkmode 구현을 위해 darkmode라는 atom을 만들었다고 생각해봅시다. 그렇다면 그 darkmode의 true or false 상태를 atom으로부터 가져와야 style을 변경하던지, 혹은 버튼의 style을 변경한다던지 핸들링이 가능해질겁니다. 그렇다면 이 상태를 어떻게 atom으로부터 가져올까요?

    //atom.tsx
    export const darkMode = atom({
    	key: 'darkmode',
    	default: false,
    });
    
    
    const darkmode = useRecoilValue(darkMode);

    우리는 다음과 같이 atom의 상태를 가져올 수 있습니다. atom.tsx에 선언되어있는 darkMode atom을 useRecoilValue를 통해 우리가 사용할 곳에서 가져와 사용할 수 있습니다. 🚀

     

    이렇게 우리가 다크모드를 사용할려고 하는데, 다크모드가 항상 true이면 사용할 이유가 없겠죠? 우리는 이 atom에 있는 상태를 핸들할 수 있어야 합니다.

     

    useSetRecoilState

    벌써부터 useState hook과 너무 닮았다고 생각이 들지 않나요? recoil도 마찬가지로 useSetRecoilState라는 함수를 통해 atom의 상태를 관리할 수 있습니다. useSetRocilState우리가 선언했던 atom을 인자로 받습니다.

     

    그리고 이 atom을 변경할 수 있는 권한을 갖는 함수를 선언한 뒤 사용합니다.

    const setToDos = useSetRecoilState(toDoState);
    const handleValid = ({ toDo }: IForm) => {
    	setToDos((prevToDos) => [{ text: toDo, category: '진행 예정', id: Date.now() }, ...prevToDos]);
    };

    프로젝트에 있는 코드 중 일부를 잘라서 가져와보았습니다. 우리는 setToDos라는 함수를 useSetRecoilState라는 함수에 인자를 받아 선언했습니다. 우리는 이 setToDos를 통해 toDoState라는 atom을 핸들링 할 수 있게 된 것입니다.

     

    저 handleValid가 실행된다면 toDoState에 변경이 가해지겠죠? 🏃🏻‍♂️

     

    Selector

    이제 recoil의 꽃 selector입니다! 우선 selector의 공식문서의 정의를 살펴봅시다.

    Selector는 파생된 상태(derived state)의 일부를 나타낸다. 파생된 상태는 상태의 변화다. 파생된 상태를 어떤 방법으로든 주어진 상태를 수정하는 순수 함수에 전달된 상태의 결과물로 생각할 수 있다.

    공식 문서에서는 다음과 같이 설명되어 있는데 바로 이해가 되지 않습니다. 역시 코드로 보는 것이 좋은 것 같습니다. 저는 이 selector를 atom에 정의한 특정 상태를 또 한 번 어떠한 방법으로 바꿀 수 있다. 라고 생각을 하였습니다.

     

    예를 들자면, 우리가 toDoState라는 배열의 length를 가져와 현재 할 일이 몇 개인지 확인해보고 싶다고 한다면, 우리는 해당 컴포넌트에서 그 배열을 그 안에서 가공해 사용할 수 있겠지만, 우리는 selector를 통해, 그 과정을 거치지 않는 순수한 형태의 todo.length를 얻을 수 있습니다.

     

    export const toDoCounterSelector = selector({
    	key: 'toDoCounterSelector',
    	get: ({ get }) => {
    		const toDos = get(toDoState);
    		return toDos.length;
    	},
    });

     

    우선 selector은 key와 get으로 이루어져있고, 이 get은 atom state를 가질 수 있습니다. 여기서 우리는 해당 atom에 변경을 가하고 그 것을 return한 순수한 toDoCounterSelector라는 새로운 배열을 가질 수 있는 것이죠.

     

    마찬가지로, 할 일에 대한 상태를 필터링해 다시 배열의 형태로 나눠 리턴하고 싶다하면,

    export const toDoStateSelector = selector({
    	key: 'toDoStateSelector',
    	get: ({ get }) => {
    		const stateToDos = get(toDoState);
    		return [
    			stateToDos.filter((stateToDoss) => stateToDoss.category === '진행 중'),
    			stateToDos.filter((stateToDoss) => stateToDoss.category === '진행 예정'),
    			stateToDos.filter((stateToDoss) => stateToDoss.category === '완료'),
    		];
    	},
    });

    우리는 이렇게 toDoStateSelector라는 새로운 Array를 가질 수 있게 되는 것입니다.

     

    이렇게 recoil에서 가장 중요한 개념들을 살펴보았습니다! 저는 개인적으로 조그마한 프로젝트던 큰 프로젝트던 recoil을 사용할 것 같습니다. hooks와 비슷한 형태라 사용하기도 더 편하고, redux에 비해 러닝커브도 작다고 생각이 들기 때문입니다👏🏻

    여러분도 사용해보고 마음에 드신다면 상태관리 라이브러리로 recoil을 사용해보는 것은 어떤가요?

     

    오늘도 글 읽어주셔서 감사합니다 도움이 되셨다면 좋겠습니다! 좋은 하루 되세요 🌈

     

    darkmode를 사용하기 위해 styled-component의 themeprovider를 사용했는데 혹시 해당 포스팅도 궁금하시다면 댓글 남겨주시면 해보도록 하겠습니다 그럼 20000! 😇

    댓글

sangjun's blog