나는 내가 뭘 쓰는지 모르겠다.

설탕유령·2022년 7월 14일
0
post-custom-banner

오늘 중간 발표에 대비해서 아키텍쳐를 그렸다.
다만 그려놓고도 고민은 왜 이 기술을 썻는가에 대해서는 나도 모르겠다는 거다.
근래 라이브러리 공식 문서를 소흘히 했다가 피 보기도 했고, 한번쯤 내가 왜 이 라이브러리를 쓰는가 고민을 해야하기에 오늘은 코딩을 쉬고 기술 조사에 치중을 하고자 한다.

기술 리스트

[에러 생성기]
TypeScript

[코딩 방해]
ESLint:
Prettier:

[스타일 용]
styled components
windi css
font awesome
sweetAlert2

[데이터 관리]
React Query
Recoil
React Hook Form

[빌드용]
Vite

[서버와 통신]
AXIOS

TypeScript


TypeScript는 JavaScript에서 추가 기능을 넣은 존재와 같다.
TypeScript가 개발 된 이유는 서버 때문이다.
JavaScript는 원래 Clint 측 언어였다. 다만 시간이 지나고 발전해 나가면서 Node 와 같이 서버 측 프로그래밍 언어로도 사용하기 시작했다.

다만 JavaScript 코드는 복잡하고 무거워졌고, 객체 지향 프로그래밍의 역할을 제대로 수행하지 못하며 서버 측 기술로 활용하기 어려웠다.
TypeScript는 그 격차를 메우기 위해 생겨났다.

정적 타입

TypeScript의 가장 큰 특징이라고 한다면 정적 타입이다
기존에 JavaScript는 변수에 형식을 지정하지 않았다.
TypeScript는 다음과 같이 변수가 할당되거나 매개변수를 선언하면 형식을 지정해야한다.

function sum(a: number, b: number) {
  return a + b;
}

정적 타입을 통해서 다음과 같은 다양한 이점을 얻을 수 있다

  • 컴파일 전 사전에 에러 탐지
  • 타입에 따른 자동 완성
  • 데이터 유효성 검증

즉 코드를 보가 읽기 쉽게 만들어주고 개발자의 실수나 오류를 컴파일 단계에서 검증하도록 도와준다.(대신 JavaScript는 무시하거나 감지 못하고 넘어가는 수많은 오류를 선물로 안겨준다)

타입 스크립트는 다양한 타입 지정을 지원한다.
1) 일반 타입
일반적으로 변수 선언시 : 표시와 함께 타입을 지정해준다.

const test: string = "this is String"

2) interface 사용
다양한 위치에서 사용되는 데이터의 통합 체크를 위해 형식을 지정해 둘 수 있음

interface test1 {
  test: string;
}
interface test1 {
  count: number;
}

// 선언 병합으로 같은 이름을 이용해도 합쳐짐  

3) type alias
interface와 비슷한 동작을 하지만 interface는 같은 이름으로 다른 속성을 선언시 선언이 병합되지만 Type Alias는 불가능

type test = {
  test: string;
}
type test = {
  count: number;
}
// 선언 병합 안되서 오류남

4) generics
정의 시점에 변수의 타입을 선언하기 어려운 경우 사용
<T>는 컨벤션이며 제네릭의 해당하는 타입에는 어떤 타입이라도 들어올 수 있고, 들어오는 값에 타입에 의해 타입 매개변수가 결정됨

function test<T>(value: T) {
	return {value}
}

const returnValue = test("this is Test");
// String이 들어온 순간 매개변수 타입이 String으로 결정 됨

TypeScript + React

사실상 이전에 했던 이야기의 반복이긴 하지만 React는 TypeScript와 궁합이 좋으며 지원또한 잘 하고 있음

1) Interface
컴포넌트를 많이 분리하고 사용하는 React 특성 상 같은 타입의 데이터를 여기저기 뿌려주는 경우가 많음 이러한 상황에 Interface를 사용해 데이터를 통합된 규격으로 관리 가능

2) 구성 요소를 이해하기 쉬움
타입이 지정되면 어떤 데이터가 들어오고, 어떤 방식으로 동작할지 유추하기 편리함

3) 코드 완성
이미 위에서 이야기한 사항이지만 타입이 지정되면 특정 위치에 어떤 타입의 데이터가 와야하는지 유추해 자동 완성 기능을 유용하게 사용 가능함

4) 주요 라이브러리에 대한 TypeScript 지원
라이브러리를 가져다 쓰는 경우 해당 라이브러리에서 지원하는 타입에 대한 유추가 어려움
리액트 생태계에서 동작하는 주요 라이브러리들은 TypeScript에 대응하기 위해 내부적으로 쓰는 타입에 대한 지원을 제공해줌

ESLint & Prettier


ESLint는 코드의 품질을 관리하기 위한 툴이다.
Prettier는 코드의 포멧을 관리하기 위한 툴이다.

ESLint는 문법적인 오류나 스타일적인 오류, 비효율적인 구조 등을 판별해 표시하거나 자동으로 고쳐준다.
Prettier는 줄 바꿈, 공백, 들여쓰기, 문자표현 방식(",') 등의 코드 스타일을 정해진 규칙에 따라 통일시켜 협업시 일관적인 코드 스타일을 유지할 수 있도록 해준다.

어찌 보면 ESLint > Prettier의 형태를 띄고 있다.
ESLint 또한 포멧팅의 기능을 가지고 있기 때문이다.
서로간에 곂치는 영역이 있기에 잘못 사용하면 서로 충돌이 일어나는데, 대표적으로는
문자열 표현시 "과 ' 방식이 충돌하는 경우가 많이 일어난다.

Prettier

Prettier는 포멧팅 기능을 가지고 있다.
문법적인 요소 보다는 좀더 단순한 코드의 형식을 지정하며 주요 규칙은 다음과 같다.

{
  "jsxSingleQuote": false, // JSX에 singe 쿼테이션 사용 여부
  "printWidth": 80, //  코드가 길어질 때 줄 바꿈을 할 기준
  "semi": true, // 세미콜론 사용 여부
  "singleQuote": true, // String을 감쌀 때 사용할 따옴표의 형식(쌍따옴표 vs 따옴표)
  "tabWidth": 2, // 탭을 넣을 때 들어갈 공백의 개수
  "useTabs": false, // 탭 사용 여부(탭이냐 공백이냐)
  "overrides": [ 
    {
      "files": "*.json",
      "options": {
        // json에서는 줄 바꿈 기준을 200으로 설정
        "printWidth": 200
      }
    }
  ], // 특정 파일별로 옵션을 다르게 지정함, ESLint 방식 사용
}

이처럼 성능에 영향을 주지 않는 범위에서 개발자 취향에 따른 코딩 스타일의 규칙을 지정한다.

ESLint

코드를 짤 때 같은 동작이라도 다른 구조를 가지도록 할 수 있다.
예를들어 ESLint에서 제공되는 기본 룰 중에는 no-extra-boolean-cast가 존재한다.
말 그대로 필요하지 않은 boolean 캐스트를 사용하지 않도록 하는 것이다

// 만약 foo 변수가 boolean인 경우 아래의 코드들은 모두 같은 동작을 한다
if (!!foo) {
    // ...
}

if (Boolean(foo)) {
    // ...
}

if (foo) {
    // ...
}

// ESLint의 자동 교정을 통해 위에 코드는 모두 아래의 방식으로 통일된다.
if (foo) {
    // ...
}

이처럼 ESLint는 Rules에 따라서 특정 구문이나 방식을 교정하거나 에러를 표시해준다.
ESLint 사용시 적용할 규칙의 프리셋을 'eslint:recommended' 이라는 이름으로 제공하며, 상세 룰은 아래 링크에서 확인 가능하다.
https://eslint.org/docs/latest/rules/
✅: eslint:recommended 사용시 적용 되는 규칙
🛠: fix 기능을 호출시 자동으로 수정되는 규칙
💡: 편집자가 수정으로 수정 가능한 규칙
개발을 하다보면 🛠 규칙은 자동적으로 수정이 진행되어 크게 신경쓰지 않아도 깔끔하고 통일된 코드를 개발 가능하다.
하지만 수정 불가능한 일부 규칙은 error를 표시하는데 주로 no-unused-vars(선언을 하고 사용하지 않은 변수 규칙)과 같은 자동 수정이 애매한 경우다.
eslint:recommended룰 말고도 제공되는 다양한 규칙 모음이 존재하는데,
React에 경우 다양한 플러그인을 활용해 환경에 맞는 규칙을 사용 가능하다
eslint-config-airbnb: 가장 대중적인 컨벤션 가이드로 airbnb 스타일의 코드 규칙을 적용 가능
eslint-config-airbnb-typescript: airbnb의 typescript 최적화된 코드 스타일 적용 가능
eslint-config-prettier: prettier의 포멧팅 기능과 충돌이 일어나는 설정을 비활성화
eslint-plugin-import: ES2015+ import/export 구문의 linting을 지원하고 import명이나 잘못 작성한 파일 경로에 대한 이슈를 방지해주는 플러그인
eslint-plugin-jsx-a11y: JSX 내의 접근성 문제에 대해 linting을 지원하는 플러그인
eslint-plugin-prettier: config가 곂치는 포멧팅을 비활성화한다면 plugin은 eslint에 prettier의 포멧팅 기능을 추가(즉 eslint 포멧팅을 비활성화 하고, prettier의 포멧팅 기능을 가져옴)
eslint-plugin-react: React에 특화된 룰을 사용하기 위한 플러그인(config가 아니라 plugin, 그저 사용을 허용하는 것이며 상세 룰은 직접 정의해야함)
eslint-plugin-react-hooks: 마찬가지로 React Hooks에 특화된 룰을 사용하기 위한 플러그인

이처럼 ESLint에서 제공되는 룰은 매우 다양하고, 사실상 수많은 에러와 규칙에 지쳐서 나중에 가면 빨간게 보인다 싶으면 잠깐 보다가 그냥 .eslintrc.js(ESLint 설정 파일)에 가서 Rules를 비활성화 시키는 경우가 허다하다

사용법에 대한 깊은 이해도가 없으니, 그냥 기능을 비활성화 해버리는 식이다.

스타일 & UI

React에서는 UI와 관련해 다양한 프레임워크가 존재한다.
정말 다양하기 때문에 어느정도 유명한 것들만 일부를 조금 알아보도록 하자.
1) MUI
아마 React 환경에서 가장 유명한 framework라고 생각한다.
Google의 Material Design 철학에 맞추어 개발된 framework다.
역사가 길고, 가장 유명한 만큼 기여자 또한 많아서 많은 자료 레퍼런스를 얻을 수 있다.
보통 UI 프레임워크는 React Bootstrap과 같이 기존에 있는 CSS 라이브러리를 기반으로 만들어지는 경우가 많은데, MUI는 시작부터 React 환경에 맞춰 개발이된 프레임워크다.
덕분에 React에 component 형식에 맞춰진 예제를 잘 제공해준다.
유료로 제공되는 템플릿을 살펴보면 깔끔하면서도 구성요소가 잘 나뉘어져 있는 느낌을 준다
https://mui.com/store/previews/otis-admin-pro-material-dashboard-react/

2) Ant Design
중국에 알리바바 그룹에서 개발한 UI 프레임워크다
https://demos.creative-tim.com/muse-vue-ant-design-dashboard/?_ga=2.235678725.566141811.1657866402-1559730598.1657866402#/dashboard
템플릿으로 보면 제법 단순하면서 깔끔한 이미지를 준다.
가볍게 사용하기 좋아보이나 중국에서 개발한 프레임워크이기 때문에 자료에 종종 중국어가 석여있거나, 참고할 수 있는 레퍼런스도 중국어가 더 많다.
3) Semantic UI React
기존에 별도로 존재하던 Semantic UI의 React 버전이다.
React 환경에 맞추기 위해서 jQuery를 들어내었다.
잠시 살펴봤지만, 아까 이야기했던 Ant와 MUI에 비해 그 구성이 작고 애니메이션 또한 적게 들어갔다.
깔끔하면서도 Docs 규모또한 작아서 별다른 이야기는 없이 넘어가려 한다.

4) React Bootstrap
우리가 잘 알고있는 Bootstrap을 React 환경에 맞추어 변형된 프레임워크다.
기존 UI framework가 React 전용으로 별도로 구성 되었기에 jQuery와 같은 불필요한 종속성을 제거했다.
Bootstrap 방식에 익숙하다면 러닝커브가 적지만, MUI 등의 프레임워크에 디자인에 비해서 특색있는 매력은 안느껴진다.
익숙한 만큼 오래된 디자인의 형태가 느껴지는 기분이다.

5) StoryBook
엄밀히 말하자면 StoryBook은 UI Framework는 아니다
다만 UI에 밀접하게 관련되어 있고 현재 내가 프로젝트에서 활용하지 않고 있기에 별도로 설명을 하고자 그냥 넣었다.
StoryBook을 설명하자면, 컴포넌트 단위로 나눠진 UI의 개발을 지원하는 UI 개발 환경 지원 도구다.
예를 들어 MUI에 button 컴포넌트를 가져오고, 다양한 속성을 미리 지정해서 실제 화면에서 어떤 형식으로 보여줄지 다양한 값과 속성에 따라서 preview가 가능하다.

해당 사진은 예시로 Button을 가져와서 하단에 속성 편집창에서 다양한 속성을 지정해서 UI를 변경해 가며 미리 보기가 가능하다

다양한 컴포넌트를 합쳐 특정 집합 단위로 테스트도 가능하다
단순히 View 테스트만이 아닌
컴포넌트의 Props를 확인하고 값을 변경하면서 Props가 바뀔때 UI의 변경과 동작을 같이 확인가능한 구성이다.

실제 구성이 개발되기 전에 미리 UI를 개발하고 구성 가능하며, 동작에 대한 테스트를 도와주고 기록을 남길 수 있는 만큼 협업성이 매우 좋지만,
준비하고 구성하고 코드를 싸는 것도 공수가 들어간다.
즉 개발 시간이 늘어난다...


이외에도 수많은 프레임워크가 존재하지만 나는 UI가 준비된 프레임워크 대신 커스터마이징이 쉬운 다른 분류의 utility-first CSS framework를 사용하고 있기 때문에 생략한다.

Styled Components

아마 어떤 UI 라이브러리르 사용하든 커스텀을 위해서 Styled Components는 프로젝트에 다들 하나씩 가지고 있을 꺼라 생각한다.

Styled Components는 Javascript 파일 내에서 CSS를 사용하기 해주는 CSS-in-JS 라이브러리다.
사용 예시는 다음과 같다.

import styled from 'styled-componets'

render(
    <Title>
      Hello World!
    </Title>
);

const Title = styled.h1`
  font-size: 1em;
  text-align: center;
`;

const 변수명의 형태로 정의된 변수에는 Styled Components로 생성된 css가 적용된 html 요소가 담기고, 페이지를 render할 때 변수명으로 css가 적용된 html 요소를 불러와 사용 가능하다

왜 사용하는거지?

컴포넌트 기반 개발 방법이 주류가 되면서 잠시 Atomic design patten을 도입을 시도한 적이 있다.
모든 요소를 작게 나눠가며 컴포넌트 단위로 동작하도록 쪼개면서 css까지 따로 분리를 하니 구성을 하나하나 찾아가면서 파악하는 시간도 늘고 오히려 너무 복잡해진 느낌이었다.
물론 그때 효율적인 분리를 하지 못한 내 잘못이지만, 컴포넌트 기반으로 개발을 할때는 나눠진 컴포넌트 내부에서 HTML, CSS, JavaScript가 모두 포함이 되는게 관리하는게 용의하다는 생각이 들었다.
그렇기 때문에 한 컴포넌트에 CSS를 포함시키기 위해 CSS-in-JS를 사용하기로 생각했다.

또한 Styled Components가 없는 경우 일반 css파일을 import 해야할 텐데, 여러 위치에서 사용되는 CSS에 경우 모듈화가 진행되어 가져와야하는 경우, css를 문서 단위로 나눠야 하기 때문에 관리가 복잡해진다.
모듈화해서 사용하자면 문서를 나눠야 하고, 문서를 나누면 유지보수 측면에서 구성이 복잡해진다. 그렇기 때문에 CSS-in-JS를 사용해 CSS를 컴포넌트화 하고자 했다.

TailwindCSS

css를 컴포넌트화 한것은 좋지만 그래도 아직 문제는 남아있다.

import styled from 'styled-componets'

render(
    <MainWrapper>
      <MainTitle>메인제목</MainTitle>
      <SubWrapper>
        <SubTitle>서브제목</SubTitle>
        ...
      </SubWrapper>
    </MainWrapper>
);

// 아래쪽에는 열심이 Styled Componets를 선언한다......

한마디로 복잡하다.
저기에 사용된 CSS가 뭔지 보려면 변수 선언부에 적힌 내용을 보고, 다른 요소들과에 연관성을 생각하려면 요소를 하나씩 찾아가면서 계산을 해야한다.

또한 디자인에 모든 요소를 직접 관리하는건 어려운 일이다.
그렇기 때문에 사람들은 Styled Componets와 함께 별도의 UI Framework를 사용한다.
이미 만들어진 예쁜 디자인을 가져다 적용시키고, 만약 필요한 커스터마이징은 Styled Components를 이용해 진행하는 형식이다.
보통은 MUI를 거론하지만, 난 별도의 목적이 있기 때문에 일단 tailwind에 대해서 이야기 하고자 한다.

tailwind는 다양한 스타일을 축약된 이름으로 className에 적용하는 것으로 디자인을 적용시킨다. 예를 들면 다음과 같은 Styled Components 예제가 있다.

const Wrapper = styled.div`
padding-bottom: 10px;
@media (min-width: 768px) {
    padding-bottom: 20px;
}
`;

render(
    <Wrapper>
        Hello world!
    </Wrapper>
);

padding을 아래쪽에 적용하고자 하지만, 다양한 사이즈를 고려하기 위해 미디어 쿼리 내용이 들어가고, 쿼리는 길어진다.
TailWind는 이러한 경우 다음과 같이 축약할 수 있다.

render(
    <div className="pb-10 md:pb-20">
        Hello World!
    </div>
);

pb-10은 아래에 padding을 10만큼 적용시키라는 뜻이고, md:는 화면크기의 범주가 md에 속하면 작동하라는 표시다.
두 예제는 동일한 동작을 하지만 TailWind에서는 축약되어 효율적인 css 사용이 가능하다.

TailWind의 가장 큰 장점은 익숙해지면 어떤 CSS가 적용되었는지 전체적으로 확인이 가능하다는 점이다.
Styled Components가 선언된 변수를 하나씩 찾아가야했다는 점에 비해서는 나름 편하다
선언이 필요없다는 점에서 class 이름에 대해서 고민하지 않아도 된다.
(Styled Components에서는 이름을 어떻게 선언할지 고민이 귀찮았다)

그럼에도 단점이 조금 있는데 바로 길어지는 className이다
아래 그림의 파란 영역은 TailWind 공식 사이트에 달린 버튼 하나에 들어가는 ClassName이다

물론 TailWind도 이러한 사항을 잘 알고,
여러가지 className을 통합해서 테마로 재사용 가능하게 해주는 apply와 같은 기능을 따로 제공한다

WindiCSS

WindiCSS는 태생부터가 TailWindCSS를 기반으로 두고 있다.
그래서 TailWindCSS 구문과 환경에 호환이 되며, 부분적으로 적용이 가능하다

WindiCSS는 기존에 Tailwind를 사용하던 개발자가 늘어나는 구성 요소만큼 늘어나는 컴파일 속도를 개선하고자 만든 framework다.

다만 새롭게 시작하는 만큼 TailWind의 고질적인 문제인 긴 ClassName의 축약이 조금 들어가있다.
상세한 내용은 https://dev.to/composite/windicss-tailwindcss-4gi6 내용에 잘 정리되어 있지만 몇개를 예시로 꺼내보고자 한다.

클래스 + 그룹핑

// TailWind 방식
<div class="bg-white dark:hover:bg-gray-800 dark:hover:font-medium dark:hover:text-white"/>

// WindiCss 방식
<div class="bg-white dark:hover:(bg-gray-800 font-medium text-white)"/>

클래스 + 반응형 디자인

// 꺽쇠 형태로 해상도 이상/ 이하를 범위로 지정할 수 있다.
<div class="p-1 md:p-2 <lg:p-3"></div>

클래스 축약어

// windi.config.js
// windiCSS 설정 상으로 여러 className을 합쳐 만든 축약어를 사용 가능
export default {
  theme: {
    /* ... */
  },
  shortcuts: {
    'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
    'btn-green': 'text-white bg-green-500 hover:bg-green-700',
  },
}

물론 TailWind도 놀고만 있는건 아니라고 ClassName을 축약하기 위한 다양한 방법을 고려중이고 일부는 WindiCSS와도 일치한다.
하지만 WindiCSS가 TailWind를 어느정도 품고 있는 형태기 때문에 두개의 프레임워크 학습을 위해, 또한 빠른 빌드를 위해 Vite를 도입한 만큼 목표와 기준을 성능으로 잡기 위해 조금은 더 빠른 WindiCSS를 채택하게 되었다.

MUI VS WindiCSS

결국 한번은 집고 넘어가야할 문제다.
MUI는 정말 다양한 기능을 제공하고 간편하게 사용이 가능하다
그런데 어째서 WindiCSS를 사용했는가?

간단히 생각한다면 MUI는 이미 만들어진걸 간편하게 그저 가져다 쓰면 된다.
다만 조금 무거울 수 있고(실제 측정은 안해봤지만...), 커스터마이징이 상대적으로 어렵다
WindiCSS는 단축키 같은 존재다.
결국엔 내가 다 구성해야하지만 커스터마이징이 자유롭고, 단순히 단축키처럼 가져다 쓰기 때문에 상대적으로 빠르다.

솔직히 MUI문서 읽어보면서 '그냥 이거 썼으면 편했을텐데'라고 생각한 적이 한두번이 아니다.
당장 필요한 carousel도 지원하고, 프로젝트에 사용해야할 다양한 icon도 지원한다.
input만 봐도 입력을 시작하는 순간 예시로 달려있던 placeholder가 위로 살짝 올라가 input의 title 역할을 하는 것도 참 부럽다.
그럼에도 굳이 불편하게 직접 다 커스터마이징 하는 이유는 학습 때문이다.

나는 CSS에 익숙하지 않다.
디자인이나 레이아웃 구성이나 모두 조금씩 내게 어렵다.
그런 의미에서 WindiCSS는 간단히 축약어를 등록하면, 해당 축약어가 어떤 역할을 하는지, 내부적으로 어떤 CSS를 품고 있는지 마우스를 가져다 대면 vscode 상으로 보여준다(물론 WindiCSS 관련 플러그인을 설치해야한다)
잘 정리된 공식 API와 축약된 className을 통해 css가 어떤 형식으로 동작하는지 좀더 쉽게 이해 가능한 창구 역할을 해준다.

또한 MUI는 디자인 아름답지만 여타 UI framework(Bootstrap 등)가 가진 문제점인 같은 프레임워크를 사용한 사이트들과 디자인이 비슷해 보이는 문제가 거슬렸다.
커스터마이징을 위해 까려하면 내부적으로 동작하는 애니메이션이 조금 걱정이 되었기에 자유로운 구성이 가능한 WindiCSS 방식을 고르게 되었다.
(물론 똥손이 커스터마이징이 자유롭다고 예쁜 디자인 나오지는 않는다는 사실을 깨달았지만, 그래도 나중에는 더 나아지겠지 하는 마음으로 하고 있다.)

마지막으로는 역시 속도 문제다.
다양한 구성, 다양한 지원, 아름답고 애니메이션이 적용된 스타일들
VS
단축키로 날것 CSS 그대로 적용시키기
후자가 좀더 속도가 빠를 것 같다.
물론 그냥 부차적인 이유다.

font awesome

결국 MUI를 안쓰기로 결정했기에 아이콘을 따로 가져올 필요를 느꼇다.
Icon 라이브러리중에 가장 유명해 다양한 아이콘을 지원하고,
별도로 React에 대한 지원을 해주기에 결정한 라이브러리다.
추가로 아이콘에 대한 커스터마이징이 편해서 애용하고 있다.

sweetAlert2 & react-toastify

둘다 사용자에게 알림을 보내기 위한 라이브러리다.
아무리 전부 커스텀으로 제작한다고 하지만 시간 공수를 고려해야하기 때문에 일부분은 라이브러리의 도움을 받고자 한다.

sweetAlert2는 좀 큰 화면으로 알람이 가고
react-toastify는 작은 알림이 간다는 차이가 있다.

현재 도입 고려중인건 sweetAlert지만, 모바일 환경을 고려하는 만큼 단순한 toastify 알람도 같이 고려중이다.

sweetAlert2의 알람 방식

react-toastify의 알람 방식

데이터 관리

React 내부적으로 데이터와 관련된 다양한 라이브러리가 존재한다.
그중 아마 대표적인 것은 redux가 아닐까?
Redux는 JavaScript 상태관리 라이브러리다
원래 근본은 Node.js에서 사용된 모듈이다

컴포넌트의 상태 업데이터 관련 로직을 분리시켜서 효율적인 관리를 위해 사용되며, 컴포넌트끼리 똑같은 상태를 공유하거나 상태 값을 전달하거나 업데이트 용으로 사용된다.

리덕스

리덕스는 다음과 같은 개념으로 나뉜다
1) 액션
상태의 어떠한 변화가 필요한 경우 액션이라는 것이 발생함

{
  type: 'ACTION_ONE'
  data: {
    id: 1,
    text: '액션 발동'
  }
}

위와 같은 형태로 type에 action의 이름을 지정하고 참고할(사용할) 값을 입력
2) 액션 생성 함수
액션 객체를 만들어 주는 함수다

function addAction(data) {
  return {
    type: 'ACTION_ONE',
    data
  }
}

3) 리듀서
변화는 일으키는 함수로 액션을 만들어서 발생시키면 리듀서가 현재 상태와 전달받은 액션 객체를 파라미터로 받아온다.
그리고 두 값을 참고해 새로운 상태를 만들어 반환한다.

function reducer(state, action) {
	switch (action.type) {
      case ACTION_ONE:
        return {
        	state.data
        }
  	  default:
  	    return null;  
    }
}

대충 짠 코드니 의미는 없고 그냥 action 타입에 따라서 다른 동작을 한다.

4) 스토어
프로젝트에 리덕스를 적용하기 위한 것으로 한개의 프로젝트는 하나의 스토어만 가질 수 있음(원칙적으로는...)
스토어 안에는 애플리케이션 상태와 리듀서 등이 포함됨

import { createStore } from "redux";
const store = createStore(reducer);

스토어를 선언할때 리듀서를 넣어서 사용한다.
5) 디스패치
디스패치는 액션을 발생시키는 것이다.
dispatch(action)의 형태로 액션 객체를 파라미터로 넣으면 호출된다.
디스패치가 호출되면 스토어는 리듀서 함수를 실행시켜 새로운 상태로 만들어 준다.

6) 구독
특정 리스너 함수를 파라미터로 받고
특정 리스너 함수가 액션이 디스패치되어 상태가 없데이트되면 호출된다.

아무튼 복잡한 구성을 이야기했고 누군가 잘 그려둔 그림을 가져오자면

대충 이런 구조인 것 같다
아무튼 복잡하다

왜 필요하지?

아무튼 이렇게 복잡하게 사용하려는 이유는 뭘까

Redux 없이 컴포넌트끼리 값을 전송하고자 하면 Props를 사용해야한다.
컴포넌트 A에서 컴포넌트 B를 호출할때 Props를 전송해야하고,
B가 C와 D 컴포넌트에게 값을 전송하고자하면 Props를 전송해야한다.
또한 D 컴포넌트에서 변경된 사항이 A, B 전체에 동기화 되어야한다고 할 때,
현재 전달된 Props는 개별적인 요소들이기 때문에 서로 연결이 안되어있다.

이런 데이터 공유 및 연동을 위해 Redux를 이용해 상태를 중앙에서 관리하고 참조하는 방식을 사용 하도록 한다.

또한 예상치 못한 데이터 조작을 막기 위해, 상태를 직접 수정하지 않고 기존에 정해진 API를 호출하는 방식으로 처리를 한다.

React Query

서버와 통신되는 데이터를 관리하기 위한 용도다
대부분의 경우는 아마 캐싱 기능을 사용해 정적인 데이터를 다시 불러오지 않고 재활용을 하고자 하는 의미로 사용 될 것이다.
하지만 나는 캐싱 기능을 사용하고 있지 않다.
정적인 데이터의 기준도 애매하기도 해서 그저 무한 스크롤(pageable) 기능만 호출해서 사용하고 있다.

Recoil

기존 Redux에서 관리되는 전역관리를 대체하는 라이브러리다.
사용 구조도 단순해서 atoms를 선언하고 그냥 가져오는 방식으로 손쉽게 사용이 가능하다
다만 사용을 하면서 느끼는 거지만, 전역관리용으로 쓰기에는 그냥 일반 전역 컨텍스트를 선언하는 것과 별다른 차이가 없다.
피드백을 받은 내용이지만, 굳이 라이브러리를 쓰지 않고도 할 수 있는 일이면 안쓰는게 더 나은 방법이라는 말을 들었다.
recoil에 대한 이해가 적기 때문에 그런것 같다.

React Hook Form

서버로 전송할 form 태그에 관련된 사항을 관리하기 위한 라이브러리다.
yup이라는 유효성 검증 라이브러리와 함께 쓰면 손쉽게 유효성에 대한 검증이 가능하고,
유동적으로 늘어나는 input 필드에 대해서도 list {}와 연계해서 데이터를 객체로 효율적인 관리가 가능하다
또한 컴포넌트를 분리시켜 사용시 리렌더링 성능에 대한 개선도 가능하다

빌드

Vite에 대한 내용은 생략한다
이미 간단한 글로 정리한 내용이 있기 때문이다.
https://velog.io/@sugar_ghost/ViteJS-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC

profile
달콤살벌
post-custom-banner

0개의 댓글