커스텀 훅 사용 예시

카테고리 Daily

오늘은 회사에서 실전투자 API 개편사항을 반영하기 위해 기존 API를 수정하는 작업을 하였다.

그러던 중, 각 컴포넌트에서 동일한 백엔드 API 로직을 발견하고 이를 커스텀 훅으로 빼내어 관리하면 유지보수성 측면과 가독성 측면에서 개선될 것이라고 판단하여 적용해보았다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 기존 코드
const checkUserStatus = async () => {
const response = await tradeInstanceAPIWithToken.post("/url", {
requestBody
});

if (response.status === 200) {
... // 응답 성공시 코드
} else if (response.status === 403) {
... // 403일 때, 실행할 코드
}
};

const [accountLoading, setAccountLoading] = useState<boolean>(false);

const getUserAccount = async () => {
setAccountLoading(true);
await tradeInstanceAPI.post("/url2").then((res) => {
if (res.status === 200) {
... // 응답 성공 시 코드
setAccountLoading(false)
}
});
};

useLayoutEffect(() => {
if (subMenu === "accounts") {
// subMenu가 accounts 일 때,
getUserAccount();
} else {
// subMenu가 myport, trading일 때
checkUserStatus();
}
}, [subMenu]);
  • checkUserStatus, getUserAccount 함수를 useLayoutEffect 훅에서 호출한다.
  • 해당 백엔드 요청 API 코드는 다룬 곳에서도 쓰이기에 함수로 빼내면 유지보수성을 높일 수 있다.
  • 가독성 측면에서도 굳이 요청 로직을 다 볼 필요가 없다.

개선된 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// useCheckUserStatus.ts
import { useState } from "react";
import { tradeInstanceAPIWithToken } from "your-api-instance";

const useCheckUserStatus = () => {
// 백엔드 API 응답과 관련된 state들
const [errorType, setErrorType] = useState<number | string | null>(null);
...

const checkUserStatus = async () => {
const response = await tradeInstanceAPIWithToken.post("/url", {
requestBody
});

if (response.status === 200) {
... // 응답 성공시 코드
} else if (response.status === 403) {
... // 403일 때, 실행할 코드
}
};

return {
errorType,
...,
checkUserStatus,
};
};

export default useCheckUserStatus;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// useGetUserAccount.ts
import { useState } from "react";
import { tradeInstanceAPI } from "your-api-instance";

const useGetUserAccount = () => {
const [userAccounts, setUserAccounts] = useState<any[]>([]);
const [accountLoading, setAccountLoading] = useState<boolean>(false);

const getUserAccount = async () => {
setAccountLoading(true);
await tradeInstanceAPI.post("/trade/get_accounts").then((res) => {
if (res.status === 200) {
const { accounts } = res.data;
setUserAccounts(accounts);
setAccountLoading(false);
}
});
};

return {
userAccounts,
accountLoading,
getUserAccount,
};
};

export default useGetUserAccount;
  • 백엔드 로직의 로딩 상태까지 캡슐화 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Main.tsx
import React, { useLayoutEffect } from 'react';
import useCheckUserStatus from './useCheckUserStatus';
import useGetUserAccount from './useGetUserAccount';

const Main = ({ user, license, isExpiredUser, subMenu }: any) => {
const { errorType, ..., checkUserStatus } = useCheckUserStat();
const { userAccounts, accountLoading, getUserAccount } = useGetUserAccount();

useLayoutEffect(() => {
if (subMenu === "accounts") {
getUserAccount();
} else {
checkUserStatus();
}
}, [subMenu]);

return (
// 여기에 컴포넌트의 JSX를 반환
);
};

export default Main;
  • 훨씬 코드가 간결해지고 가독성도 높아져서 추후에 유지보수할 때 시간을 많이 절약할 수 있을 것 같다.
  • 앞으로 서비스의 코드를 이런식으로 분리해보는 연습을 해봐야겠다.

댓글 공유

  • page 1 of 1

loco9939

author.bio


author.job