Skip to content

기술 스택

HGW edited this page Oct 1, 2023 · 43 revisions

🐎 rushstack eslint

대형 팀과 프로젝트를 위해 설계된 TypeScript ESLint 규칙 세트이다. 큰 규모의 팀과 프로젝트에서 발생할 수 있는 문제를 해결하기 위해 고안 되었다.

📚 Storybook

Storybook은 UI 컴포넌트 개발 도구이다. 앱과는 독립된 환경에서 UI 컴포넌트를 개발하고 디자인 할 수 있게 해준다.

storybook 사용을 위한 패키지는 다음과 같다.

패키지명 설명
@storybook/addon-essentials Storybook에서 필수적인 기능을 제공하는 애드온 패키지로, 스토리북의 핵심 기능과 통합된 다양한 도구 및 유틸리티를 포함하는 패키지
@storybook/addon-interactions 사용자 상호작용과 관련된 스토리북 애드온으로, 컴포넌트의 상호작용을 테스트하고 시각적으로 확인하는 데 도움을 주는 도구를 제공하는 패키지
@storybook/addon-links 스토리북 스토리 간의 네비게이션과 링크 생성을 가능하게 해주는 애드온으로, 스토리 간 이동 및 상호 연결을 쉽게 설정할 수 있게 해주는 패키지
@storybook/addon-onboarding 사용자를 위한 스토리북 온보딩 기능을 제공하는 애드온으로, 스토리북을 처음 사용하는 사용자에게 안내 및 도움말을 제공하는 패키지
@storybook/blocks 스토리북 블록 패턴을 생성하고 공유하는 데 사용되는 패키지로, 컴포넌트 디자인 패턴을 문서화하고 공유하기 위한 템플릿을 제공
@storybook/react React 애플리케이션을 위한 스토리북 패키지로, React 컴포넌트를 개발하고 시각적으로 확인하는 데 필요한 기본 스토리북 설정을 제공
@storybook/react-vite Vite와 함께 React 애플리케이션을 개발할 때 사용되는 스토리북 통합 패키지로, Vite와의 호환성을 갖춘 React 프로젝트에서 스토리북을 실행하도록 도움을 줌
@storybook/testing-library 테스팅 라이브러리와 스토리북을 통합하는 애드온으로, 테스트를 위해 사용자 인터페이스 컴포넌트를 효과적으로 검증하고 테스트하는 데 도움을 줌
@storybook/addon-styling 추가 예정

⁉️ 애드온 : 소프트웨어나 애플리케이션에 추가 기능 또는 확장 기능을 제공하는 모듈 또는 구성 요소를 의미한다.

🌪️ TailwindCSS

CSS 문서로 가지 않고 오직 HTML 문서 내에서 빠르게 웹 사이트 구축을 가능하게 한다. utility-first 기법을 사용하여 미리 구현된 CSS를 사용한다.

tailwindcss 사용을 위한 패키지는 다음과 같다.

패키지명 설명
postcss pure css로 변환해주는 전처리 패키지
autoprefixer 벤더 프리픽스 자동 삽입 패키지

색상은 팔레트로 관리한다.

colors: {
  main: { base: '#59473C', darken: '#311B0E', lighten: '#8C6F5E' },
  active: {
    base: '#FF7A00',
    darken: '#D76700',
    lighten: '#FFC998',
    lightest: '#FFE6CE'
  },
  sub: {
    blue: '#487DAD',
    sky: '#CCF7FA',
    red: '#FF3D00',
    lime: '#40DF32',
    green: '#349E2C'
  },
  gray: {
    100: '#F1F1F1',
    200: '#DCDDDE',
    300: '#8A8A8A',
    400: '#5F5F5F',
    500: '#313131'
  },
  white: '#ffffff',
  black: '#000000'
}

폰트는 OAGothic을 사용한다.

🪂 React Query

React-Query는 서버의 값을 클라이언트에 가져오거나, 캐싱, 값 업데이트, 에러 핸들링 등 비동기 과정을 더욱 편하게 하는데 사용된다.

기본 사용법

  1. 클라이언트를 초기화 해준다.
const queryClient = new QueryClient()
  1. QueryClientProvider로 어플리케이션을 감싸준다.
<QueryClientProvider client={queryClient}>
  <Example />
</QueryClientProvider>
  1. 필요한 컴포넌트(<Example />)에서 react-qurey 에서 제공하는 useQuery, useMutation 등을 사용하면 된다.

파일 상단에는 사용하는 키들을 객체로 관리한다.

const channelKeys = {
  all: ['channels'] as const,
  detail: (id: number) => [...channelKeys.all, id] as const,
  ...
};
  • API 관련 함수 이름은 동사+명사로 통일한다.
  • 쿼리 관련 함수 이름은 use+API 관련 함수로 통일한다.

useQuery 예시

const getChannels = async (): Promise<Channel[]> => {
  const response = await axios.get('/channels');

  return response.data;
};

export const useGetChannels = () => {
  return useQuery({ queryKey: [channelKeys.all], queryFn: getChannels, initialData: [] });
};

useMutation 예시

const createChannel = async ({ authRequired, description, name }: Create) => {
  return await axios.post('/channels/create', {
    ...관련 코드
  });
};

export const useCreateChannel = () => {
  return useMutation({ mutationFn: createChannel });
};

사용할 때 다음과 같은 방식으로 사용한다.

  • useQuery관련 훅, useMutation 관련 훅 순서대로 배치한다.
  • useQuery의 경우 훅의 이름에서 명사만을 사용한다.
  • useMutation의 경우 훅의 이름에서 동사+명사만을 사용한다.
  const { data: channels } = useGetChannels();
  const { data: posts } = useGetPosts();
  ...

  const { mutate: createChannel } = useCreateChannel();
  const { mutate: createPost } = useCreatePost();
  ...

useInfiniteQuery

  • 특정 조건에서 데이터를 추가적으로 받아오는 기능 구현을 지원해준다.
  • 무한 스크롤 기능 구현에 이용된다.
  • 첫 번째 인자로 queryKey(필수), 두번째 인자로 queryFn(필수), 세번째 인자로 options(선택)를 받는다.
  • useInfiniteQuerydata, isFetchingNextPage, isFetchingPreviousPage, fetchNextPage, fetchPreviousPage, hasNextPage 등을 반환한다.
  • 세번째 인자로 들어가는 주요 옵션에는 pageParam이라는 프로퍼티가 존재하며 queryFn에 할당해줘야 한다. 이때 기본값으로 초기 페이지 값을 설정 해줘야한다.
    • getNextPageParam, getPreviousPageParam 을 이용해서 pageParam 값을 변경 가능하다.
  • 무한 스크롤 구현을 위해 getNextPageParam을 이용했다.
    • getNextPageParam을 이용해서 다음에 불러올 페이지를 설정하고 반환해준다. 반환값은 queryFn의 파라미터로 넘어간다.
flowchart TD;
    A[getNextPageParam 반환값] --> B[pageParam];
    B --> C[fetchFn의 파라미터로 들어감];
Loading
  • getNextPageParam은 첫번째 인자로 lastPage를, 두번째 인자로 allPages를 받는데 lastPage는 fetch 해온 가장 최근에 가져온 페이지 목록이다.
    • 만약 lastPage.length === 0 이라면 더이상 불러올 정보가 없는 것으로 간주해 getNextPageParamundefined를 반환하게 하게했다.
    • 이는 스크롤을 다 내렸을시 다시 fetchFn이 실행되지 않게해 네트워크 낭비 이슈를 막아주는 역할을 한다.
  • useInfiniteQuery를 사용해서 useInfiniteScroll 커스텀 hook을 생성
    • 사용법
const fetchApi = async ({  limit, offset }: Props): Promise<Data[]> => {
  const response = await snsApiClient.get(`/api/temp`, {
    params: { limit, offset }
  });

  return response.data
};

export const useFetchApi = ({ channelId, limit }: Omit<Props, 'offset'>) => {
  return useInfiniteScroll({
    fetchData: (pageParam) => fetchApi({ channelId, limit, offset: pageParam })
  });
};

const { data } = useGetApi({ limit: 5 });

return (
  <div>
    {data.pages.map((pageData, pageIndex) => (
      <ul key={pageIndex}>
        {pageData.map((item) => (
          <li key={item.id}>{item.title}</li>
        ))}
      </ul>
    ))}
  </div>
);

⚡️ React Router

클라이언트 사이드에서 이뤄지는 라우팅을 간단하게 해주는 라이브러리이다.

관련 경로는 상수로 관리한다.

export const PATH = {
  HOME: '/',
  PROFILE: '/profile',
  ...
}

⏰ dayjs

JavaScript 에서 사용할 수 있는 날짜, 시간 조작에 관련된 라이브러리이다.

import dayjs from 'dayjs';

const formattedTime = dayjs(포맷할시간변수).format('YYYY/MM/DD'); // '연도/달/일'로 출력된다.

포맷에 쓰이는 키워드들은 dayjs 문서에서 확인할 수 있다.