React-Query + Recoil 을 사용하여 SessionStorage에 상태 값 저장하기
React-Query로 비동기 API 통신으로 얻은 값을 Recoil을 사용하여 저장하지만, 새로고침을 클릭할 경우 값이 날아갈 수 있다. 이런 경우, SessionStorage나 LocalStorage에 저장하여 값을 유지할 수 있는데 오늘은 SessionStorage에 저장하는 방법을 알아보자.
2023.04.04 - [개발 Study/React] - [React/Recoil] Recoil 을 상태관리 라이브러리로 선택한 이유
1. 상태 값 Atom으로 생성하기
recoil폴더 내에 필요한 상태 값을 저장할 .ts 파일을 생성하고, 아래와 같이 예시로 작성한다.
export const oneAccountState = atom<IOneAccountInfo>({
key: "oneAccountState",
default: {
oneToken: "",
uid: -1,
mid: -1,
name: "",
handphone: "",
pwYN: "N",
termsYN: "Y",
status: "Y",
jsonData: [],
resYN: "N",
resCode: -1,
resMsg: "",
},
effects: [
({ onSet }) => {
onSet((newValue, oldValue, isReset) => {
isReset
? sessionStorage.removeItem("oneAccountState")
: sessionStorage.setItem("oneAccountState", JSON.stringify(newValue));
});
},
],
});
IOneAccountInfo Interface를 타입으로 갖는 로그인 상태를 Atom으로 생성한다. 코드를 살펴보면, key 값을 string으로 갖고있고 저 key값으로 스토리지에 상태 값이 저장된다. default 옵션으로 초기 값을 지정해놓을 수 있다. effects에서 atom 변경 시 부수적으로 실행되는 함수가 있는데 onSet()함수다. 파라미터로 newValue, oldValue, isReset을 받는데 초기화인 경우 sessionStorage에서 'oneAccountState' 키 값을 갖는 아이템을 지워주고, 아닌 경우 새로 받은 값을 stringify해서 'oneAccountState'에 넣어준다.
2. React-Query로 useMutation 훅 생성하기
mutation은 파라미터를 받아서 mutationFn(함수)을 실행시키고 실행시켜 받아온 값을 return해 준다. 보통 데이터를 생성, 삭제, 변형 등을 할 때 사용되는 훅이다.
보통 React 에서 훅은 function component 내에서만 선언이 가능하며, mutation만 따로 빼서 관리를 해주고 싶은 경우, function으로 한 번 더 감싸서 custom hook 형태로 만들어주면 된다.
CustomHook 내에서 mutation도 사용하고, API 통신에서 나온 결과 값을 recoil로 한번에 저장해주기 위해 아래와 같이 코드를 구현했다.
export const oneAuthMutation = () => {
const setOneAccountState = useSetRecoilState(oneAccountState);
return useMutation<IOneAccountInfo, AxiosError, IOneLoginInput, any>({
mutationFn: async (input) => {
return axios({
method: "post",
url: `${baseURL}/Auth`,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
data: input,
}).then((response) => {
return response.data;
});
},
onError: (err) => {
console.log(err);
},
onSuccess: (data: IOneAccountInfo, args) => {
setOneAccountState(data);
},
});
};
`useSetRecoilState`는 상태 값을 저장하기 위해 사용하는 훅으로, 상태를 읽어올 순 없고 값을 저장할때만 쓸 수있다.
1번에서 생성한 oneAccountState에 저장하기 위해 setOneAccountState를 선언한다. 그리고 useMutation 훅을 return해주는데 useMutation 안을 살펴보자. 우선 Typescript 를 사용하기 때문에 <> 내에 <data로 받아오는 타입, error가 발생했을 경우 return되는 타입, mutationFn에 parameter로 들어가는 타입, context 타입> 으로 설정해주면 된다.
mutationFn에서 실행시킬 api 호출 함수를 넣어준다. axios 라이브러리를 활용하여 비동기 통신을 연결해주고 post방식으로 통신한다. onError()는 에러가 났을 경우 실행되는 코드를 넣어준다. onSuccess()에서는 mutation 성공 시 recoil로 상태값이 저장되도록 setOneAccountState()에 데이터를 넣어준다.
3. Mutation 실행하기
로그인 페이지에서 id/pw 입력 후 로그인 버튼을 누르면 onSubmit 함수가 실행되고 그 안에서 recoil로 로그인정보도 저장하고, 인증 api도 실행시킨다.
function Login() {
const authMutation = oneAuthMutation(); // 로그인 Mutation
const [loginInput, setLoginInput] = useRecoilState(oneLoginState);
/*form관련 validation함수 생략*/
const onSubmit = async (data: IOneLoginInput) => {
data.appType = "W";
setLoginInput(data); // 로그인 정보 저장
authMutation.mutateAsync(data); // Auth API 실행
};
return (
<>
<GlobalStyle />
<Wrapper>
<div className="register-form">
<Form onSubmit={handleSubmit(onSubmit)}>
{/* <HeaderImg /> */}
<div className="form-group">
<Input
type="text"
{...register("userId")}
className={`form-control ${errors.userId ? "is-invalid" : ""}`}
/>
<div className="invalid-feedback">{errors.userId?.message}</div>
</div>
<div className="form-group">
<Input
type="password"
{...register("userPw")}
className={`form-control ${errors.userPw ? "is-invalid" : ""}`}
/>
<div className="invalid-feedback">{errors.userPw?.message}</div>
</div>
<Button disabled={isSubmitting}>로그인</Button>{" "}
{/* isSubmitting : 제출 끝날 때까지 버튼 비활성화 */}
</Form>
</div>
</Wrapper>
</>
);
}
useRecoilState로 로그인 정보를 저장하거나 읽을 수 있다. 2번에서와 다르게 읽고쓰기가 가능하도록 하는 훅이다. 로그인 시 제출되는 정보를 oneLoginState에 담기 위해 setLoginInput()함수에 제출된 data를 넣어준다. 그리고 제출된 data로 2번에서 작성한 인증용 muation을 실행시킨다.
mutation이 성공적으로 실행되면 위와 같이 SessionStorage에 저장된다.
'개발 Study > React' 카테고리의 다른 글
[Vite/React] Vite에서 env 파일로 환경 변수 사용하기 (0) | 2023.06.13 |
---|---|
[React/TypeScript] VSCode code snippet 사용법 (0) | 2023.06.09 |
[React/Recoil] Recoil 을 상태관리 라이브러리로 선택한 이유 (6) | 2023.04.04 |
[React] React-Query를 사용하는 이유? (Feat.Redux) (0) | 2023.04.03 |
[React/Vite] CRA(Create-React-App) 프로젝트를 Vite 로 변환하기 (0) | 2023.03.27 |
댓글