Skip to content

Commit

Permalink
fix(Leaderboard): Segment 변경 시 불필요한 재렌더링
Browse files Browse the repository at this point in the history
SegmentedControl 변경시 재렌더링될 필요 없는 부분까지 되는 문제
ex. SegmentedControl, PromoSelect
loading, error, !data 처리를 내부 -Result 컴포넌트에서 처리하는 방식으로
해결하였습니다.
  • Loading branch information
yoopark committed Oct 9, 2023
1 parent 054fde0 commit 420d7e2
Show file tree
Hide file tree
Showing 15 changed files with 667 additions and 458 deletions.
2 changes: 1 addition & 1 deletion app/src/@shared/components/Pagination/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ARIA_LABEL } from '@shared/constants/accessibility';
import { Clickable, HStack } from '@shared/ui-kit';
import { PageButton } from './PageButton';

type PaginationProps = {
export type PaginationProps = {
currPageNumber: number;
onPageNumberChange: (pageNumber: number) => void;
totalPageNumber: number;
Expand Down
67 changes: 0 additions & 67 deletions app/src/Leaderboard/components/Leaderboard/LeaderboardHeader.tsx

This file was deleted.

14 changes: 14 additions & 0 deletions app/src/Leaderboard/components/LeaderboardPagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
Pagination,
type PaginationProps,
} from '@shared/components/Pagination';
import { useDeviceType } from '@shared/utils/react-responsive/useDeviceType';

type LeaderboardPaginationProps = Omit<PaginationProps, 'pagePerRow'>;

export function LeaderboardPagination(props: LeaderboardPaginationProps) {
const device = useDeviceType();
const pagePerRow = device === 'mobile' ? 5 : 10;

return <Pagination {...props} pagePerRow={pagePerRow} />;
}
31 changes: 31 additions & 0 deletions app/src/Leaderboard/components/PromoSelect/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Promo } from '@shared/__generated__/graphql';
import { Select, SelectContent, SelectTrigger } from '@shared/ui-kit';
import { numberWithUnitFormatter } from '@shared/utils/formatters/numberWithUnitFormatter';

import { PromoSelectList } from './PromoSelectList';

type PromoSelectProps = {
curr: number | null;
list: Promo[];
onChange: (promo: string | null) => void;
};

export function PromoSelect({ curr, list, onChange }: PromoSelectProps) {
const unit = '기';

return (
<Select
width="21rem"
onValueChange={onChange}
defaultValue={curr !== null ? curr.toString() : undefined}
defaultRenderValue={
curr !== null ? numberWithUnitFormatter(curr, unit) : undefined
}
>
<SelectTrigger placeholder="전체" />
<SelectContent maxHeight="20rem">
<PromoSelectList list={list} />
</SelectContent>
</Select>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LeaderboardListItemSkeleteon } from './LeaderboardListItemSkeleton';

export const LeaderboardResultSkeleton = () => {
return (
<VStack w="100%" spacing="2rem" style={{ marginTop: '4rem' }}>
<VStack w="100%" spacing="2rem" style={{ marginTop: '2.4rem' }}>
<LeaderboardListItemSkeleteon />
<VStack w="100%" spacing="0.5rem">
{Array.from({ length: 50 }, (x) => x).map((_, idx) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { QueryResult } from '@apollo/client';
import { useAtomValue } from 'jotai';
import { useSearchParams } from 'react-router-dom';

import { leaderboardArgsAtom } from '@/Leaderboard/atoms/leaderboardArgsAtom';
import { Leaderboard } from '@/Leaderboard/components/Leaderboard';
import { LeaderboardDateDescriptor } from '@/Leaderboard/components/Leaderboard/LeaderboardDateDescriptor';
import { LeaderboardPagination } from '@/Leaderboard/components/LeaderboardPagination';
import { LeaderboardResultSkeleton } from '@/Leaderboard/components/skeletons/LeaderboardResultSkeleton';
import { SIZE_PER_PAGE } from '@/Leaderboard/constants/defaultOptions';
import { LEADERBOARD_PARAM_KEYS } from '@/Leaderboard/constants/paramKeys';
import {
DateTemplate,
GetLeaderboardCommentQuery,
} from '@shared/__generated__/graphql';
import { FullPageApolloErrorView } from '@shared/components/ApolloError/FullPageApolloErrorView';
import { HStack, Spacer, VStack } from '@shared/ui-kit';

type LeaderboardCommentResultProps = {
result: QueryResult<
GetLeaderboardCommentQuery,
{
dateTemplate: DateTemplate;
pageNumber: number;
promo: number | null;
pageSize: number;
}
>;
};

export function LeaderboardCommentResult({
result: { loading, error, data },
}: LeaderboardCommentResultProps) {
const [_, setSearchParams] = useSearchParams();
const params = new URLSearchParams();

const { PROMO, PAGE } = LEADERBOARD_PARAM_KEYS;

const leaderboardArgs = useAtomValue(leaderboardArgsAtom);

if (leaderboardArgs === null) {
throw new Error('leaderboardArgs is null');
}

const { promo, pageNumber } = leaderboardArgs;

function handlePageNumberChange(pageNumber: number) {
if (promo) {
params.set(PROMO, promo.toString());
}
params.set(PAGE, pageNumber.toString());

setSearchParams(params);
}

if (loading) {
return <LeaderboardResultSkeleton />;
}
if (error) {
return <FullPageApolloErrorView message={error.message} />;
}
if (!data) {
return <LeaderboardResultSkeleton />;
}

const {
data: {
me,
totalRanking: { nodes, totalCount },
},
start,
end,
} = data.getLeaderboardComment.byDateTemplate;

const unit = '자';

return (
<VStack w="100%" spacing="4rem">
<VStack w="100%" spacing="1rem">
<HStack w="100%">
<Spacer />
<LeaderboardDateDescriptor
start={new Date(start)}
end={new Date(end)}
/>
</HStack>
<Leaderboard me={me} list={nodes} unit={unit} />
</VStack>
<LeaderboardPagination
currPageNumber={pageNumber}
onPageNumberChange={handlePageNumberChange}
totalPageNumber={Math.ceil(totalCount / SIZE_PER_PAGE)}
/>
</VStack>
);
}
96 changes: 22 additions & 74 deletions app/src/Leaderboard/pages/Comment/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,43 @@ import { useAtomValue } from 'jotai';
import { useSearchParams } from 'react-router-dom';

import { leaderboardArgsAtom } from '@/Leaderboard/atoms/leaderboardArgsAtom';
import { Leaderboard } from '@/Leaderboard/components/Leaderboard';
import { LeaderboardHeader } from '@/Leaderboard/components/Leaderboard/LeaderboardHeader';
import { LeaderboardResultSkeleton } from '@/Leaderboard/components/skeletons/LeaderboardResultSkeleton';
import {
LEADERBOARD_DEFAULT_OPTIONS,
SIZE_PER_PAGE,
} from '@/Leaderboard/constants/defaultOptions';
import { leaderboardPromoListAtom } from '@/Leaderboard/atoms/leaderboardPromoListAtom';
import { PromoSelect } from '@/Leaderboard/components/PromoSelect';
import { LEADERBOARD_DEFAULT_OPTIONS } from '@/Leaderboard/constants/defaultOptions';
import { LEADERBOARD_PARAM_KEYS } from '@/Leaderboard/constants/paramKeys';
import { Footer } from '@core/components/Footer';
import { DateTemplate } from '@shared/__generated__/graphql';
import { FullPageApolloErrorView } from '@shared/components/ApolloError/FullPageApolloErrorView';
import { Pagination } from '@shared/components/Pagination';
import { Seo } from '@shared/components/Seo';
import { DeferredComponent, VStack } from '@shared/ui-kit';
import { useDeviceType } from '@shared/utils/react-responsive/useDeviceType';
import { HStack, VStack } from '@shared/ui-kit';

import { LeaderboardCommentResult } from './components/LeaderboardCommentResult';
import { GET_LEADERBOARD_COMMENT } from './queries/getLeaderboardComment';

export default function LeaderboardCommentPage() {
const device = useDeviceType();
const [_, setSearchParams] = useSearchParams();
const { PAGE, PROMO } = LEADERBOARD_PARAM_KEYS;
const { PROMO } = LEADERBOARD_PARAM_KEYS;

const leaderboardArgs = useAtomValue(leaderboardArgsAtom);

if (leaderboardArgs === null) {
throw new Error('leaderboardArgs is null');
}

const { loading, error, data } = useQuery(GET_LEADERBOARD_COMMENT, {
const promoList = useAtomValue(leaderboardPromoListAtom);

if (promoList === null) {
throw new Error('promoList is null');
}

const result = useQuery(GET_LEADERBOARD_COMMENT, {
variables: {
...LEADERBOARD_DEFAULT_OPTIONS,
...leaderboardArgs,
dateTemplate: DateTemplate.Total,
},
});

const { promo, pageNumber } = leaderboardArgs;
const { promo } = leaderboardArgs;

function handlePromoChange(promo: string | null) {
const params = new URLSearchParams();
Expand All @@ -52,69 +51,18 @@ export default function LeaderboardCommentPage() {
setSearchParams(params);
}

function handlePageNumberChange(pageNumber: number) {
const params = new URLSearchParams();

if (promo) {
params.set(PROMO, promo.toString());
}
params.set(PAGE, pageNumber.toString());

setSearchParams(params);
}

if (loading) {
return (
<DeferredComponent>
<LeaderboardResultSkeleton />
</DeferredComponent>
);
}
if (error) {
return (
<DeferredComponent>
<FullPageApolloErrorView message={error.message} />
</DeferredComponent>
);
}
if (!data) {
return (
<DeferredComponent>
<LeaderboardResultSkeleton />
</DeferredComponent>
);
}

const {
data: {
me,
totalRanking: { nodes, totalCount },
},
start,
end,
} = data.getLeaderboardComment.byDateTemplate;

const unit = '자';

return (
<>
<Seo title="랭킹 › 코멘트 길이" />
<VStack w="100%" spacing="6rem">
<VStack w="100%" spacing="2rem">
<LeaderboardHeader
currPromo={promo}
onPromoChange={handlePromoChange}
start={new Date(start)}
end={new Date(end)}
<VStack w="100%" spacing="1rem">
<HStack w="100%" justify="start">
<PromoSelect
curr={promo}
onChange={handlePromoChange}
list={promoList}
/>
<Leaderboard me={me} list={nodes} unit={unit} />
</VStack>
<Pagination
currPageNumber={pageNumber}
onPageNumberChange={handlePageNumberChange}
totalPageNumber={Math.ceil(totalCount / SIZE_PER_PAGE)}
pagePerRow={device === 'mobile' ? 5 : 10}
/>
</HStack>
<LeaderboardCommentResult result={result} />
</VStack>
<Footer />
</>
Expand Down
Loading

0 comments on commit 420d7e2

Please sign in to comment.