Skip to content

Commit 3583236

Browse files
[25.02.25] Fix - useSearchParam > 제네릭 사용하여 타입 추론 정확히 하도록 수정 (#14)
* [25.02.16 / TASK-118] Feature: 채널톡 추가 및 헤더 로고 클릭 동작 추가 (#13) * hotfix: 일부 오류 수정 username 관련 오류 및 SSR 렌더린 관련 오류로 추정되는 오류 수정 * feat: 채널톡 추가 및 헤더 로고 동작 추가 * refactor: console.log 제거 * refactor: 메세지 내용 변경 * refactor: 코멘트 반영 겸 자잘한 오류 해결 * refactor: username 관련 코드 수정 * refactor: ENV 오류 전용 공통 오류 객체 추가 * hotfix: env 값 추가 * hotfix: env 관련 오류 해결 * hotfix: 구조분해 관련 오류 해결 * fix: useSearchParam > 제네릭 사용하여 타입 추론 정확히 하도록 수정 --------- Co-authored-by: 육기준 <[email protected]>
1 parent d920968 commit 3583236

File tree

9 files changed

+43
-29
lines changed

9 files changed

+43
-29
lines changed

.github/workflows/docker-publish.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
echo "NEXT_PUBLIC_ABORT_MS=${{ secrets.NEXT_PUBLIC_ABORT_MS }}" >> .env
3232
echo "NEXT_PUBLIC_EVENT_LOG=${{ secrets.NEXT_PUBLIC_EVENT_LOG }}" >> .env
3333
echo "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" >> .env
34+
echo "NEXT_PUBLIC_CHANNELTALK_PLUGIN_KEY=${{ secrets.NEXT_PUBLIC_CHANNELTALK_PLUGIN_KEY }}" >> .env
3435
echo "SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env
3536
cp .env .env.production
3637

src/app/(with-tracker)/(auth-required)/leaderboards/Content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const data = [
1616

1717
export const Content = () => {
1818
const width = useResponsive();
19-
const { setSearchParams } = useSearchParam();
19+
const [, setSearchParams] = useSearchParam();
2020

2121
return (
2222
<div className="flex w-full h-full flex-col gap-[30px] overflow-auto items-center max-TBL:gap-5">

src/app/(with-tracker)/(auth-required)/main/Content.tsx

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,23 @@
33
import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
44
import { useEffect } from 'react';
55
import { useInView } from 'react-intersection-observer';
6-
import {
7-
Button,
8-
Dropdown,
9-
Section,
10-
Summary,
11-
Check,
12-
OptionType,
13-
} from '@/components';
6+
import { Button, Dropdown, Section, Summary, Check } from '@/components';
147
import { postList, postSummary } from '@/apis';
15-
import { PATHS } from '@/constants';
8+
import { PATHS, SORT_TYPE } from '@/constants';
169
import { useSearchParam } from '@/hooks/useSearchParam';
1710
import { trackUserEvent, MessageEnum } from '@/utils/trackUtil';
11+
import { SortKey, SortValue } from '@/types';
1812

19-
const sorts: Array<OptionType> = [
20-
['작성일순', ''],
21-
['조회순', 'dailyViewCount'],
22-
['좋아요순', 'dailyLikeCount'],
23-
];
13+
const sorts: Array<[SortKey, SortValue]> = Object.entries(SORT_TYPE) as Array<
14+
[SortKey, SortValue]
15+
>;
2416

2517
export const Content = () => {
26-
const { searchParams, setSearchParams } = useSearchParam();
18+
const [searchParams, setSearchParams] = useSearchParam<{
19+
asc: 'true' | 'false';
20+
sort: SortValue;
21+
}>();
22+
2723
const { ref, inView } = useInView();
2824

2925
const { data: posts, fetchNextPage } = useInfiniteQuery({
@@ -83,20 +79,21 @@ export const Content = () => {
8379
onChange={() => {
8480
trackUserEvent(MessageEnum.SORT_INTERACT_MAIN);
8581
setSearchParams({
86-
asc: `${!(searchParams.asc === 'true')}`,
82+
asc: searchParams.asc === 'true' ? 'false' : 'true',
8783
});
8884
}}
8985
checked={searchParams.asc === 'true'}
9086
label="오름차순"
9187
/>
9288
<Dropdown
9389
defaultValue={
94-
sorts.find((i) => i[1] === searchParams.sort) as OptionType
90+
sorts.find((i) => i[1] === searchParams.sort) ??
91+
SORT_TYPE['작성일순']
9592
}
9693
options={sorts}
9794
onChange={(data) => {
9895
trackUserEvent(MessageEnum.SORT_INTERACT_MAIN);
99-
setSearchParams({ sort: encodeURI(data as string) });
96+
setSearchParams({ sort: data as SortValue });
10097
}}
10198
/>
10299
</div>

src/components/auth-required/main/Section/index.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,17 @@ export const Section = (p: PostType) => {
1515
const client = useQueryClient();
1616

1717
const { username } = client.getQueryData([PATHS.ME]) as UserDto;
18-
const { NEXT_PUBLIC_VELOG_URL } = process.env;
18+
const URL = process.env.NEXT_PUBLIC_VELOG_URL;
1919

2020
if (!username) {
2121
throw new UserNameNotFoundError();
2222
}
23-
if (NEXT_PUBLIC_VELOG_URL) {
23+
24+
if (!URL) {
2425
throw new EnvNotFoundError('NEXT_PUBLIC_VELOG_URL');
2526
}
2627

27-
const url = `${process.env.NEXT_PUBLIC_VELOG_URL}/@${username}/${p.slug}`;
28+
const url = `${URL}/@${username}/${p.slug}`;
2829

2930
return (
3031
<section className="flex flex-col w-full h-fit relative">

src/constants/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './colors.constant';
33
export * from './sizes.constant';
44
export * from './paths.constant';
55
export * from './fonts.constant';
6+
export * from './searchParams.constant';
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const SORT_TYPE = {
2+
작성일순: '',
3+
조회순: 'dailyViewCount',
4+
좋아요순: 'dailyLikeCount',
5+
} as const;

src/hooks/useSearchParam.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
import { useSearchParams, useRouter, usePathname } from 'next/navigation';
22

3-
export const useSearchParam = () => {
3+
export const useSearchParam = <T extends Record<string, string>>() => {
44
const router = useRouter();
55
const pathname = usePathname();
66
const _searchParams = useSearchParams();
77
const searchParams = new URLSearchParams(_searchParams.toString());
88

9-
const setNewParams = (newParams: Record<string, string>) => {
9+
const setNewParams = (newParams: Partial<T>) => {
1010
for (const [key, value] of Object.entries(newParams)) {
1111
if (value !== undefined && value !== null) searchParams.set(key, value);
1212
else searchParams.delete(key);
1313
}
1414
return searchParams.toString();
1515
};
1616

17-
const setSearchParams = (newParams: Record<string, string>) => {
17+
const setSearchParams = (
18+
newParams: Partial<T>,
19+
isReplace: boolean = false,
20+
) => {
21+
if (isReplace) router.replace(`${pathname}?${setNewParams(newParams)}`);
22+
1823
return router.push(`${pathname}?${setNewParams(newParams)}`);
1924
};
2025

21-
return {
22-
searchParams: Object.fromEntries(searchParams),
23-
setSearchParams,
24-
};
26+
return [Object.fromEntries(searchParams) as T, setSearchParams] as const;
2527
};

src/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export * from './dashboard.type';
22
export * from './user.type';
3+
export * from './searchParams.type';

src/types/searchParams.type.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { SORT_TYPE } from '@/constants';
2+
3+
export type SortKey = '작성일순' | '조회순' | '좋아요순';
4+
export type SortValue = (typeof SORT_TYPE)[keyof typeof SORT_TYPE];
5+
6+
export type SortType = Record<SortKey, string>;

0 commit comments

Comments
 (0)