-
Notifications
You must be signed in to change notification settings - Fork 0
기술 스택
jgjgill edited this page Nov 9, 2023
·
6 revisions
tailwind
에서 제공하는 유틸리티를 위주로 사용한다.
- 피그마에서 모호한 부분이 발생하면 유틸리티에 우선순위를 둔다.
- 작은 쪽과 큰 쪽이 같으면 작은 쪽으로 통일시킨다.
React Query 관련 코드는 _hooks/query
폴더에서 관리한다.
폴더 내에는 관리되는 데이터에 대한 파일들로 구성한다. 파일에는 다음과 같은 항목이 구성된다.
- 타입
- 키 객체
- api 함수
- query 함수
- mutation 함수
type TodoType = {
userId: number;
id: number;
title: string;
completed: boolean;
};
export const todoKeys = {
all: ['todos'] as const,
};
- 선언했던 타입을 할당한다.
- 주의 사항: fetch는 추후 axios로 변경될 예정
export const getTodos = async (): Promise<TodoType[]> => {
const response = await fetch('https://jsonplaceholder.typicode.com/todos', {
method: 'GET',
headers: { 'Content-Type': 'application/json;charset=UTF-8' },
});
const data = await response.json();
if (!response.ok) {
if (data.message) {
throw new Error(data.message);
}
throw new Error('알 수 없는 에러');
}
return data;
};
const createTodo = async ({ userId, id, title, completed }: Create) => {
return fetch('/todos/create', {
...관련 코드
});
};
- 초기 데이터가
undefined
가 나오는 것을 방지하기 위해useSuspenseQuery
를 사용한다. - 선언했던 키 객체를 사용해 키 값을 할당한다.
export const useGetTodos = () => {
return useSuspenseQuery({ queryKey: [todoKeys.all], queryFn: getTodos });
};
export const useCreateTodo = () => {
return useMutation({ mutationFn: createTodo });
};
서버 컴포넌트에서 초기 데이터를 받아서 사용할 수 있다. 다음과 같은 코드 구성이 필요하다.
- 키 객체와 api 함수를 불러와야 한다. (이와 관련해서 키 객체와 api 함수의 위치는 추후에 변경될 수 있다.)
export default async function Home() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery({
queryKey: [todoKeys.all],
queryFn: getTodos,
});
return (
...
<HydrationBoundary state={dehydrate(queryClient)}>
<QueryTest />
</HydrationBoundary>
);
}
클라이언트 컴포넌트에서는 다음과 같이 사용할 수 있다. 초기 데이터가 성공적으로 받아진다.
const QueryTest = () => {
const { data: todos } = useGetTodos();
console.log(todos);
return <div>query test</div>;
};
클라이언트 컴포넌트에서 사용할 때는 다음과 같은 형태로 사용하고자 한다.
- useQuery관련 훅, useMutation 관련 훅 순서대로 배치한다.
- useQuery의 경우 훅의 이름에서
명사
만을 사용한다. - useMutation의 경우 훅의 이름에서
동사+명사
만을 사용한다.
const { data: channels } = useGetChannels();
const { data: posts } = useGetPosts();
...
const { mutate: createChannel } = useCreateChannel();
const { mutate: createPost } = useCreatePost();
참고 문서
React Query에서 타입적으로 undefined
를 없애기 위해 useSuspenseQuery
를 사용했다.
여기서 suspense
를 통해 성공만을 가정할 수 있었지만 에러에 대한 처리도 필요하다.
이를 위해 Error Boundary를 사용할 필요가 있는데 NextJS에서 error.tsx
파일에서 기본적으로 내장되어 있다.
NextJS에서 제공하는 기본 error.tsx
예제 코드는 다음과 같다.
'use client' // Error components must be Client Components
import { useEffect } from 'react'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error)
}, [error])
return (
<div>
<h2>Something went wrong!</h2>
<button
onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}
>
Try again
</button>
</div>
)
}
-
_mocks/handlers
경로에 테스트할 목록 관련 폴더를 구성한다. - 도메인 폴더에서
handler.ts
,mock.ts
파일을 사용한다. -
handler
파일에는 테스트할 api 코드,mock
파일에는 테스트에 사용되는 데이터를 추가한다. -
handlers.ts
파일에서 사용되는handler
배열을 추가한다.
export const tempHandler = [
http.get('/mocks/api', () => {
console.log('Captured a "GET /mocks/api" request');
return HttpResponse.json({ test: 'temp get mock data' });
}),
http.post('/mocks/api', async ({ request }) => {
const data = await request.json();
console.log('Captured a "POST /mocks/api" request, data: ', data);
return HttpResponse.json({ test: 'temp post mock data' });
}),
];
export const ITEM = [사용되는 데이터 구성]
import { itemHandler } from './item/handler';
const handlers = [...tempHandler];
export default handlers;
http.get('/mocks/api/items/stores', async ({ request }) => {
await delay(1000);
const url = new URL(request.url);
const memberId = url.searchParams.get('member-id');
const size = Number(url.searchParams.get('size'));
const page = Number(url.searchParams.get('page'));
if (!memberId || !size || !page) {
return new HttpResponse(null, { status: 404 });
}
const results = ITEMS.slice(0, page * size);
return HttpResponse.json(results);
}),
http.get('/mocks/api/items/:itemId', async ({ params }) => {
await delay(1000);
const { itemId } = params;
if (!itemId) {
return new HttpResponse(null, { status: 404 });
}
const results = ITEMS[Number(itemId) - 1];
return HttpResponse.json(results);
}),
http.post('/mocks/api/items', async ({ request }) => {
await delay(1000);
const newPost = (await request.json()) as Omit<
ItemType,
'itemId' | 'storeId'
>;
const results = { itemId: ITEMS.length, storeId: 1, ...newPost };
return HttpResponse.json(results);
}),
page.tsx
에서 클라이언트 컴포넌트를 구성하여 msw
를 사용할 시 에러가 발생할 수 있다.
(msw 관련 문제인 것 같은데 아직 확실하지 않다.. 배포 api에서도 테스트가 필요한 상황..)
msw를 사용하는 테스트 환경에서는 useSuspenseQuery
를 사용하면 에러가 발생한다.
그래서 테스트 환경에서는 useQuery
를 사용해야 합니다.
(추후 배포 api에서 useSuspenseQuery
테스트 진행 예정)