자바스크립트 + 리액트 디자인 패턴을 공부하며 리액트 디자인 패턴 중 고차 컴포넌트 조합을 사용해 로딩 컴포넌트를 분리하는 예시를 접하게 되었다. 이 패턴이 WorkConnect에서 react-query를 사용하면서 로딩 컴포넌트를 계속해서 반복해서 작성해야 했던 문제를 해결할 수 있는 좋은 방법이 될 거 같다는 생각이 들어 직접 적용해 보기로 하였다.
먼저, Loading과 Error컴포넌트를 호출하는 공통 컴포넌트로 WithLoader를 제작해보자
const WithLoaderError = ({ Element, isLoading, isError }: WithLoaderErrorProps) => {
if (isLoading) return <Loading />;
if (isError) return <NotFoundError />;
return <Element />;
};
Loading,Error, Element를 반환한다.이전
const Homepage = () => {
return <HomeMain />
}
HomeMain 컴포넌트를 호출하는 역할이후
const Homepage = () => {
const workspaceId = useWorkspaceId();
const workspaceUserId = useUserStore((state) => state.workspaceUserId);
const { workspaceUser, isPending: userIsPending, isError: userIsError } = useWorkspaceUser(workspaceUserId);
const {
workspaceUserList,
isPending: userListIsPending,
isError: userListIsError
} = useWorkspaceUserList(workspaceId, workspaceUserId);
const isLoading = userIsPending || userListIsPending;
const isError = userIsError || userListIsError;
return (
<WithLoaderError
Element={() => (
<HomeMain
workspaceId={workspaceId}
workspaceUserId={workspaceUserId}
workspaceUser={workspaceUser}
workspaceUserList={workspaceUserList}
/>
)}
isLoading={isLoading}
isError={isError}
/>
);
};
이전
const HomeMain = () => {
const workspaceId = useWorkspaceId();
const workspaceUserId = useUserStore((state) => state.workspaceUserId);
const { workspaceUser, isPending: userIsPending, isError: userIsError } = useWorkspaceUser(workspaceUserId);
const {
workspaceUserList,
isPending: userListIsPending,
isError: userListIsError
} = useWorkspaceUserList(workspaceId, workspaceUserId);
if (userIsPending || userListIsPending) return <Loading />;
if (!workspaceUser || userIsError || userListIsError) return <NotFoundError />;
return (
<div className="px-[16px] mt-[26px] lg:mt-[22px] lg:pl-[42px] lg:pr-[16px] lg:gap-[42px]">
<HomeMemberCard workspaceId={workspaceId} workspaceUserId={workspaceUserId} workspaceUser={workspaceUser} />
<MemberList workspaceUserList={workspaceUserList} />
</div>
);
};
이후
const HomeMain = ({ workspaceId, workspaceUserId, workspaceUser, workspaceUserList }: HomeMainProps) => {
return (
<div className="px-[16px] mt-[26px] lg:mt-[22px] lg:pl-[42px] lg:pr-[16px] lg:gap-[42px]">
<HomeMemberCard workspaceId={workspaceId} workspaceUserId={workspaceUserId} workspaceUser={workspaceUser} />
<MemberList workspaceUserList={workspaceUserList} />
</div>
);
};
const Profile = () => {
...
return (
<WithLoaderError
Element={() => (
<ProfileMain
workspaceUser={workspaceUser}
workspaceId={workspaceId}
targetWorkspaceUserId={targetWorkspaceUserId}
/>
)}
isLoading={isPending}
isError={isError}
/>
);
};
컴포넌트의 역할을 분리하는데 성공히였지만 고차 컴포넌트에도 단점이 존재한다.
기존 컴포넌트의 깊이
<HomePage>
<HomeMain/>
</HomePage>
변경된 컴포넌트의 깊이
<HomePage>
<WithLoaderError>
<HomeMain/>
</WithLoaderError>
</HomePage>
