1. Recoil이란?
Recoil은 Facebook에서 제작한 React를 위한 상태 관리 라이브러리입니다.
Reocil 공식 홈페이지: https://recoiljs.org/ko/
프론트엔드에서 상태 관리를 매우 중요한 요소입니다. 상태 관리를 통하여 서비스나 프로그램의 동작을 예측 가능하도록 만들고, 버그를 줄이며, 코드를 더욱 효율적으로 작성할 수 있도록 도와줍니다.
2. 많은 상태 관리 라이브러리 중에 왜 Recoil을 사용할까?
최근 많은 React 프로젝트에서 Reocil을 통하여 상태 관리를 진행하는 것을 심심치 않게 볼 수 있는데, 제가 생각하고 적용해보며 느낀 선정 이유는 아래와 같습니다.
- 간결하고 직관적인 API
Recoil의 API는 간결하고 직관적입니다. 상태를 생성하려면 atom을, 상태를 변환하려면 useRecoilState 혹은 useSetRecoilState를 사용하면 됩니다. 추가로 파생 상태(Derived State)를 생성할 때에는 selector를 사용합니다.
import { atom, selector } from "recoil";
// 상태 생성
export const decimalState = atom({
key: 'decimal',
default: 0,
});
// 파생 상태(derived state)
export const binaryState = selector({
key: 'binary';
get: ({get}) => {
// decimal -> dinary의 변환값 제공
const binary = get(decimalState).toString(2);
return binary;
}.
set: ({set}, newValue) => {
const decimal = parseInt(newValue, 2);
set(decimalState, decimal);
}.
});
- 컴포넌트 간 쉬운 상태 공유
Recoil을 사용하면 컴포넌트 간에 상태를 쉽게 공유할 수 있습니다. useRecoilState 또는 useRecoilValue 훅을 사용하면 됩니다.
아래 경우를 예를 들자면
useRecoilValue은 useRecoilState(textState)의 text와
useSetRecoilState는 useRecoilState(textState)의 setText와 동일한 역할을 수행합니다.
function TextInput() {
const [text, setText] = useRecoilState(textState);
const onChange = (event) => {
setText(event.target.value);
};
return <input type="text" value={text} onChange={onChange} />;
}
function CharacterCount() {
const count = useRecoilValue(charCountState);
return <>Character Count: {count}</>;
}
- 동기 및 비동기 데이터 쿼리를 위한 유틸리티 제공
Recoil은 selector을 통하여 동기 및 비동기 데이터 쿼리를 쉽게 처리를 할 수 있습니다.
get 함수는 비동기 로직을 포함할 수 있기 때문에, API 호출 등을 Recoil을 통하여 처리할 수도 있습니다.
const fetchUserState = selector({
key: 'fetchUserState',
get: async () => {
const response = await fetch('/api/user');
const user = await response.json();
return user;
},
});
여담으로 2022년 동계 방학 때 진행하였던 새해 떡국 만들기 프로젝트에서도 쉬운 간단한 사용법이라는 하나의 이유만으로 채택한 적이 있었습니다. 팀원들 모두 REST API 요청, 전역 상태 관리 모두 처음 진행하였음에도 곧바로 적용할 수 있었습니다.
3. 실제 사용 적용 예시
앞서 언급한 새해 떡국 만들기 프로젝트에서 적용하였던 예시를 살펴보고자 합니다. 해당 프로젝트에서는 회원 정보를 기록하기 위하여 Recoil을 사용하였습니다.
// https://github.com/jangsumi/Making-Tteokguk-FE/blob/main/src/atom.jsx
import {atom} from "recoil";
import { recoilPersist } from "recoil-persist";
const { persistAtom } = recoilPersist();
export const IDState = atom({
key: 'IDState',
default: {ref: null, kakao: null, link: null}, // 비로그인 사용자
effects_UNSTABLE: [persistAtom],
});
atom을 사용하여 회원 정보를 저장해둘 상태 IDState를 생성하였습니다. default value를 모두 null로 설정하는 것으로 로그인 사용자와 비로그인 사용자를 구별하였습니다.
effect_UNSTABLE을 [persistAtom]으로 설정하여 새로고침 시, 전역 상태 IDState가 사라지는 현상을 방지하였습니다.
// https://github.com/jangsumi/Making-Tteokguk-FE/blob/main/src/pages/Main/KakaoAuth.jsx
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import SyncLoader from "react-spinners/SyncLoader.js";
import { getMyFridge } from "../../axios/refrigerator-service";
import LoginErrorModal from "../../components/Modal/LoginErrorModal";
import { Container } from "./styles";
import {useSetRecoilState} from "recoil";
import {IDState} from "../../atom.jsx";
const KakaoAuth = () => {
const setUserID = useSetRecoilState(IDState);
const [showModal, setShowModal] = useState(false);
const confirmEvent = () => {
setShowModal(false);
navigate("/");
};
const navigate = useNavigate();
useEffect(() => {
const code = new URL(window.location.href).searchParams.get("code");
axios
.get(`${import.meta.env.VITE_APP_API_URI}?code=${code}`)
.then((res) => {
if (res.status === 200) {
// 카카오계정 연결에 성공한 경우, 회원 정보 유무 확인
getMyFridge(res.data.toString()).then((data) => {
if (!data) {
navigate("/init", { state: { kakaoId: res.data } });
} else {
setUserID({ ref: data.id, kakao: data.kakaoId, link: data.link });
navigate(`/refrigerator/${data.kakaoId}`);
}
});
}
})
.catch(() => setShowModal(true));
}, []);
return (
<Container>
<SyncLoader color="#DD7592" margin={4} size={12} />
<>카카오 계정을 연결하고 있어요.</>
{showModal && <LoginErrorModal onConfirmClick={() => confirmEvent()} />}
</Container>
);
};
export default KakaoAuth;
위 코드에서 useSetRecoilState를 사용하여 IDState를 변경하는 setter 함수를 setUserID에 담아둔 것을 확인할 수 있습니다. 이 setUserID는 회원 정보가 있는 경우에 IDState의 ref에는 data.id, kakao에는 data.kakaoId, link에는 data.link를 저장해두는 것을 볼 수 있습니다.
4. 마치며...
Recoil을 처음 알게 되었던 2022년 겨울까지만 해도 React에서 상태 관리는 대부분 Redux로 진행되었던 것 같은데 최근에 다시 React를 조금씩 건드리면서 Recoil의 적용 예시가 부쩍 늘어난 것을 체감할 수 있었습니다(사실 저는 Redux는 사용해본 적이 없습니다..! 그나마 비슷한 건.. NgRx??).
React를 이용한 첫 API 연결, 상태 관리, 배포 프로젝트였던 떡국 만들기 프로젝트에서 사용한 Recoil이어서 그런지 더욱 애정이 가는 것 같습니다. 다음에 React 프로젝트를 진행할 때에는 Recoil 사용도 고려해보면 좋을 것 같네요 :)
긴 글 읽어주셔서 감사합니다!
'Web > React' 카테고리의 다른 글
[React] React에서 API 호출을 효과적으로 막는 방법 - useRef 활용하기 (0) | 2024.11.22 |
---|---|
[React] Warning: React has detected a change in the order of Hooks 에러 해결하기 (0) | 2024.07.17 |
[React] 접근 제한을 위한 Private Route 만들기 (0) | 2024.04.21 |
[React] Invalid Hook Call Warning 해결하기 (0) | 2024.04.15 |
[React + Vite] "Failed to load resource: the server responded with a status of 404(not found)" 해결하기 (0) | 2023.11.16 |