🤔 문제 발생
최종 프로젝트를 진행할때는 몰랐는데 지금 와서 리팩토링을 하다보니 사용성에 있어서 아쉬운 점이 보였다.
바로 탄소 배출량 계산 히스토리 부분이다.
여기에는 여러 작고 큰 문제들이 보이기 시작했다.
일단 몇가지 큰 오류가 있는데
1. 로딩화면
맨 처음 나오는 로딩화면은 훨씬 길다(캡쳐 시 크롭).
2. 로딩 후 화면 이동
로딩 후 화면 이동 시 데이터가 제대로 들어가지 않고 순차적으로 들어오는 것을 볼 수 있다.
나는 분명 `Promise.all`을 이용해서 모든 데이터들을 묶어줬는데 왜 그런걸까..
3. 화면 재로딩
크롬에서 탭을 통해 다른 곳으로 이동했다 오면 다시 로딩이 된다. 그럼 위의 로직을 다시 타게 된다.
💻 기존 코드
const ResultPageMain = () => {
const [userAvgData, setUserAvgData] = useState<number>(0);
const [myAllData, setMyAllData] = useState<MonthlyData[] | null>(null);
const [myAllAvgData, setMyAllAvgData] = useState<number>(0);
const [userTopData, setUserTopData] = useState<TopData | null>(null);
const [userAllData, setUserAllData] = useState<MonthlyData[] | null>(null);
const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
const [isLoading, setIsLoading] = useState(true);
const { user } = userStore();
// 유저 이미지 가지고 오기
const levelInfo = calculateLevelInfo(userInfo?.user_point ?? 0);
useEffect(() => {
const getUserFetch = async () => {
const res = await getUserInfo(user.id);
setUserInfo(res);
};
const fetchData = async () => {
try {
await Promise.all([
loadUsersAvgData(setUserAvgData), // 유저 토탈 데이터
loadMyData({
setMyAllData,
setMyAllAvgData,
selectedYear: null
}),
loadTopUsersData(setUserTopData), // 유저 최고 데이터
loadRecentFiveMonthsEmissions(currentYear, currentMonth, 2).then(
(data) => {
setUserAllData(data);
}
),
getUserFetch()
]);
// 모든 데이터가 성공적으로 패칭되면 로딩 상태를 false로 변경
setIsLoading(false);
} catch (error) {
console.error("데이터를 불러오는 중 오류가 발생했습니다:", error);
setIsLoading(false);
}
};
fetchData();
}, [user]);
if (isLoading) {
return (
<Loading
message="탄소 배출량 히스토리 로딩 중"
subMessage="잠시만 기다려 주세요~!"
/>
);
}
console.log(myAllData);
...
💡 문제 해결
const ResultPageMain = () => {
// 유저정보 가지고 오기
const { user } = userStore();
const { userInfo, isLoading: isUserInfoLoading } = useUserFetch(
user?.id ?? null
);
// 유저 이미지 가지고 오기
const levelInfo = calculateLevelInfo(userInfo?.user_point ?? 0);
// 내 데이터값 가지고 오기
const { data: carbonData, isLoading: isMyDataLoading } = useCarbonRecords({
selectedYear: null
});
const { records: myAllData, avgEmission: myAllAvgData } = carbonData ?? {
records: [],
avgEmission: 0
};
// 유저 평균 데이터값 가지고 오기
const {
userAvgData,
isLoading: isAvgDataLoading,
error: userAvgDataError
} = useUsersAvgData();
// 제일 높은 데이터값 가지고 오기
const {
topUser,
isLoading: isTopUserLoading,
error: topUserError
} = useTopUsersData();
// 유저평균 최신달 2개 가지고 오기
const {
data: emissionsData,
isLoading: isEmissionsLoading,
error: emissionsError
} = useRecentFiveMonthsEmissions(currentYear, currentMonth, 2);
if (
isMyDataLoading ||
isAvgDataLoading ||
isTopUserLoading ||
isUserInfoLoading ||
isEmissionsLoading
) {
return (
<Loading
message="탄소 배출량 히스토리 로딩 중"
subMessage="잠시만 기다려 주세요~!"
/>
);
}
if (userAvgDataError || topUserError || emissionsError) {
return <div>에러가 발생했습니다.</div>;
}
...
기존 `useState` 사용했던 것을 `Hooks`나 `Tanstack Query` 사용으로 변경했다.
(이 페이지에서는 데이터가 갑자기 변경되는 내용이 없기때문에 딱히 `Tanstack Query`를 사용하지 않아도 괜찮았지만, 공부 차원에서 몇개만 변경을 했었다.)
처음 이 페이지에서 데이터를 페칭할때 `Promise.all`을 사용하면 데이터를 한번에 병렬로 가지고 오겠지? 라는 생각으로 작성을 했었는데 막상 구현을 해보니 그러지 않았다. 아마도 useEffect 내무에서 작성이 됨과 동시에 각자가 가지고 있는 로직 내부에서 또한 페칭 시 useEffect가 발행해서 여러번 출력이 되었던게 아닌가 싶다.
하지만 위와 같이 `hooks`나 `Tanstack Query`를 사용하니까 이런 중복적으로 데이터를 가지고 오거나 충돌이 나지 않아 데이터가 빨리 불러와 지게 된다.
실질적으로 약 8배 이상의 단축 시같을 보여줬다.
이렇게 해결하니 로딩화면 이후에 화면 이동이 되었을 때 즉각 적으로 데이터가 보였다.
마지막으로 `useEffect`에서 의존성배열에 `user`라는 값을 넣어 크롬에서 탭 이동 시 데이터가 다시 캐싱되는 부분이 있었는데 자연스럽게 해결이 되었다.
병렬 처리와 캐싱으로 더 빠르게 데이터를 로딩 할 수 있게 변경을 해봤는데 확실히 엄청나게 많은 성능 개선을 이룬 것 같다.
이번 영상은 로딩을 처음부터 다 보여줬는데 정말 빠르게 처리가 되는 것을 볼 수 있다. (배속 아님 ㅎㅎ)
그리고 마지막으로 라이트하우스를 통해 성능 개선한 점수를 보여주고 해당 글을 마무리하려고 한다.
왼쪽: 리팩토링 전
오른쪽 : 리팩토링 후
리팩토링 전에도 93점이면 높은 점수이긴 하지만 아마도 첫 데이터를 가지고 올 때 한번의 기준으로 정해진 듯 하다.
(여러번의 useEffect로 데이터를 관리하던 로직에 대해서는 정확하게 점수를 주지 못하는 것 같다.)
리팩토링 이후 99점이라는 매우 높은 점수로 올라갔다는 점과 여러 이슈들을 한번에 잡을 수 있었기 때문에 아주 좋은 리팩토링이 되지 않았나 싶다.
'프론트엔드 > Next.js' 카테고리의 다른 글
[최종 프로젝트 - 리팩토링] 컴포넌트 동적 활용 (0) | 2024.12.04 |
---|---|
[최종 프로젝트 - 리팩토링] props 구조분해할당 (0) | 2024.12.02 |
[최종 프로젝트] 문자열 값에 대한 type 정의 (0) | 2024.11.09 |
[최종 프로젝트] 비슷한 두개의 컴포넌트를 효율적으로 사용하기 (0) | 2024.11.08 |
[최종 프로젝트] React 함수, 매개변수: 가독성을 높이는 작은 습관 (0) | 2024.11.02 |