이글은 2021년 5월 6일에 작성된 오래된 글이며 그때 당시 저의 부족한 지식으로 작성된 글입니다.
Apollo를 쓰면 복잡한 Redux처럼 상태관리 라이브러리가 필요없다! 라는 글들을 많이 봤을 것입니다. 저 또한 Apollo Client를 접하기 전까지는 전역 상태 관리를 위해 React에서는 Redux를 사용했고 Angular에서는 ngxs라는 상태 관리 라이브러리를 이용했습니다. 그런데 이런 상태 관리 라이브러리를 의존 한다는 거 자체가 코드가 복잡하고 양이 늘어나기 때문에 많은 개발자들이 상태 관리 관련 코드 리팩토링을 위해 많은 시간과 에너지를 쓰고있습니다. 특히 React + Redux사용시 action, reducer, type 코드들 때문에 머리가 어지러워지고 데이터 통신, 비동기 처리, 에러 처리 처럼 다양한 상황들에 대응하기 위해 상태관리는 더 복잡해집니다.
더 너아가 ‘이대론 안되겠다!’ 라는 심정으로 코드를 간결하게 만들어보겠다고 Redux 미들웨어인 saga나 thunk를 도입하게 되는 순간 내가 짠 코드를 이해하기위해 많은 시간을 쓰게 되는 자신을 보게 될 것입니다. 그래서 ducks패턴 처럼 다양한 상태관리 디자인 패턴을 찾아보고 적용해보지만 리팩토링의 고수가 아니라면 빠듯한 일정에 금방 포기하게 됩니다. (지금 까지 저의 경험담이었습니다 😂)
그러다가 새롭게 시작한 프로젝트의 서버가 apollo로 만들게 되어서 프론트도 자연스럽게 데이터 통신을 위해 Apollo Client를 사용하게 되었습니다.
React Apollo Client의 주 기능은 useQuery, useMutation, useSubscribe를 사용하여 데이터를 통신하고 클라이언트 측에서 데이터를 자동으로 캐싱해주므로 빠른 응답과 서버 자원을 절약 합니다. 하지만 이번에 글에서는 Apollo Client의 주기능은 아니지만 숨겨진 꿀 기능인 Apollo Client 전역 상태 관리 방법을 소개 해보겠습니다. 이글을 다 읽게 되면 왜 Apollo를 쓰면 Redux같은 전역 상태 관리 라이브러리를 안써도 되는지 이해하게 될 것입니다.
1. store 생성
// stores/apply
import { makeVar } from "@apollo/client";
export const applyVar = makeVar({ time: "오전 9시 - 11시" });
export const setTime = (time) => {
applyVar({ time: time });
};
time이라는 값을 전역을 관리하고 다면 makVar에 time을 선언해줍니다. makeVar는 redux로 치면 selector와 disfetch를 동시에 관리한다고 생각하면 이해가 쉬울 것입니다. 직관적인 이해를 위해 상태관리 할 변수의applyVar의 값 설정을 setTime()로 두른것입니다.
2. 컴포넌트 생성
// @component/common/TimeSelectButton
import * as applyStore from "@stores/apply";
import React from "react";
import styled from "styled-components";
import { useReactiveVar } from "@apollo/client";
export default function TimeSelectButton({ width, height, value, children }) {
const $applyStore = useReactiveVar(applyStore.applyVar);
const handleSelectButton = () => {
applyStore.setTime(value);
};
return (
<>
<StyledTimeSelectButton
width={width}
height={height}
onClick={handleSelectButton}
type="button"
className={$applyStore.time === value ? "selected" : ""}
>
{children}
</StyledTimeSelectButton>
</>
);
}
const StyledTimeSelectButton = styled.button`
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
cursor: pointer;
width: ${(props) => props.width};
height: ${(props) => props.height};
z-index: 2;
border-radius: 0;
border: none;
padding: 0;
background-color: ${({ theme }) => theme.colors.B_3};
color: ${({ theme }) => theme.colors.B_A};
&:focus {
box-shadow: none;
}
&.selected {
background-color: transparent;
color: ${({ theme }) => theme.colors.G_B};
border: 1px solid ${({ theme }) => theme.colors.G_B};
}
`;
간단한 예를 위해 시간을 선택하는 버튼 컴포넌트를 만들었습니다. import * as applyStore from "@stores/apply";로 applyStore를 가지고 옵니다. 동시에 const $applyStore = useReactiveVar(applyStore.applyVar); 를 통해 applyStore 의 상태변화 감지를 합니다. 버튼 클릭시 applyStore.setTime(value);를 통해 전역 상태 관리 중인 applyVar의 time값을 변경해줍니다.
3. 컴포넌트 사용
import TimeSelectButton from "@components/common/TimeSelectButton";
const Apply = () => {
return (
<>
<TimeSelectButton width="32%" height="80px" value="오전 9시 - 11시">
<span>오전 9시 - 11시</span>
</TimeSelectButton>
<TimeSelectButton width="32%" height="80px" value="오후 12시 - 15시">
<span>오후 12시 - 15시</span>
</TimeSelectButton>
<TimeSelectButton width="32%" height="80px" value="오후 16시 - 18시">
<span>오후 16시 - 18시</span>
</TimeSelectButton>
</>
)
}
export default Apply;
2번에 만든 시간 선택 버튼을 나열합니다.
결론
redux처럼 action, reducer, type설정같은거 없습니다! 그러니까 전역 상태 관리 코드가 5줄밖에 안나옵니다! 그러면 데이터의 비동기 처리, 에러 처리, 로딩 처리 같은거 어떻게 합니까? 그런것은 이미 Apollo를 사용 중이라면 useQuery, useMutation, useSubscribe에서 자연스럽게 작업이 되어있을것입니다. 네.. 여러분 Apollo로 한번쯤은 꼭 써보시길 추천합니다. 너무 재밌어요!!
'기억보단 기록을 > React' 카테고리의 다른 글
[React] 스타일 작업 방식 이대로 괜찮은가? (0) | 2023.05.21 |
---|---|
React Chart Library 조사 (0) | 2023.05.10 |
React Canvas로 폭죽 효과 만들기 (0) | 2023.05.10 |
React JS — Architecture + Folder Structure (0) | 2023.05.09 |