Developer

[유데미X웅진씽크빅X스나이퍼팩토리] React 2기 - 사전직무교육 3일차

yunicornlab 2024. 8. 21. 13:05
반응형

오늘은 (연습용) 프로젝트를 새로 시작하고 환경 설정한 후에 스타일링하는 법에 대해 배웠다.
 

Vite로 React 프로젝트 시작하기

React 프로젝트 시작할 때 이제는 Create React App을 사용하지 않고 Vite를 사용하는 것이 좋다.
Vite를 사용해야 하는 이유는
https://ko.vitejs.dev/guide/why

Vite

Vite, 차세대 프런트엔드 개발 툴

ko.vitejs.dev

 
 
vite로 프로젝트를 시작하려면
npm create vite@latest 폴더이름(새 폴더 안만들고 현재 폴더에 설치하고싶으면 마침표(.) 붙이기
이후 npm install 까지 입력하면 패키지들이 설치가 된다.
 
참고로, npm install 패키지이름
이렇게 하면 지정한 패키지가 설치되는 것이고
npm install만 하면
package.json에 의존성으로 적혀있는 패키지들이 일괄적으로 설치되는 것이다.


node_modules 폴더와 package-lock.json은 건드리지 말자ㅎㅎ
깃허브에 올릴때도 .gitignore에 적어서(이미 추가되어있기도 함) 업로드에는 제외시키자.
혹시나 에러 해결을 위해 구글 검색할 때 node_modules 폴더를 직접 수정하라는 멘트가 보이면 가급적 다른 방법을 찾자.
 

React에서 스타일링 적용하기

1. 모듈 css를 사용하는 방법

css 코드를 작성하고 그 파일을 "이름.modules.css"로 지정해주고,

import styles from "./css/App.modules.css";

이때, styles 말고 다른 이름으로 정해줘도 되지만, 모듈 css를 불러올땐 보통 styles라는 이름을 사용한다.
그리고 모듈 css를 사용할 때는 태그 선택자로 사용하면 안된다. class 이름 기반으로 적용되기 때문에 class 선택자를 사용해줘야한다. 하지만 클래스 선택 후 자식이나 형제 선택에는 태그 선택이 가능하다. 처음 선택할때만 주의하자!
 
하지만 현업에서는 모듈 css"만" 사용하지는 않고, classnames라는 서드파티 라이브러리를 같이 사용한다고 한다!!
여러 클래스를 같이 적용하거나 조건부로 적용할 때 유용하다.
https://www.npmjs.com/package/classnames

classnames

A simple utility for conditionally joining classNames together. Latest version: 2.5.1, last published: 8 months ago. Start using classnames in your project by running `npm i classnames`. There are 43929 other projects in the npm registry using classnames.

www.npmjs.com

// App.tsx
import styles from "./css/App.module.css";
import classNames from "classnames/bind";

const App = () => {
  const cx = classNames.bind(styles);
  const isTrue = true;

  return (
    <>
      <h1>App Component</h1>
      <p className={cx("desc", "underline")}>Sample Text</p>
      <p className={cx("desc", { underline: isTrue })}>Sample Text</p>
    </>
  );
};
export default App;

 
이렇게 classnames/bind를 import해주고, styles와 classnames를 바인딩해준다.
"cx", "classNames"는 변경할 수 있는 이름인데, 보통 이런 이름으로 많이 사용한다고 한다.
 

2. Tailwind CSS

먼저 Tailwind CSS를 설치하는 방법은 아래 페이지가 알려주는 대로 따라하면 된다.
지금 새 프로젝트를 Create React App을 사용한 게 아니라 Vite를 사용한 것이기 때문에 Vite를 선택한 링크이다.
https://tailwindcss.com/docs/guides/vite

Install Tailwind CSS with Vite - Tailwind CSS

Setting up Tailwind CSS in a Vite project.

tailwindcss.com

참고로, 위 공식문서에서 나온 설치 방법 중 3단계에서

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

이런 코드를 tailwindcss.config에 적어달라는 안내가 있는데, 저기의 content 부분은 tailwind를 적용할 content를 정하는 부분이다.
index.html 파일과 src 하위의 모든 파일(**)을 대상으로 하는데, 이때 확장자가 js, ts, jsx, tsx인 파일들에만 적용하겠다라는 의미이다.
 
모듈 CSS를 사용할 때 classnames를 같이 사용했듯이,
Tailwind CSS를 사용할 때도 tailwind-merge를 같이 사용한다고 한다.
https://www.npmjs.com/package/tailwind-merge

tailwind-merge

Merge Tailwind CSS classes without style conflicts. Latest version: 2.5.2, last published: 9 days ago. Start using tailwind-merge in your project by running `npm i tailwind-merge`. There are 3395 other projects in the npm registry using tailwind-merge.

www.npmjs.com

스타일 충돌 없이 Tailwind CSS 클래스를 JS로 효율적으로 병합하는 유틸리티 함수라고 한다.
이걸 사용하지 않고 그냥 클래스 여러개를 나열해서 사용하면, 우선순위 때문에 중첩되어서 적용이 되지 않는 문제가 발생한다고 한다.
tailwind-merge의 twMerge를 사용하면 자동 병합과 조건 처리를 의도한대로 편하게 작성할 수 있다.

import { twMerge } from "tailwind-merge";

const App = () => {
  const isError = true;
  return (
    <>
      <h1
        className={twMerge(
          "text-green-500",
          "text-5xl",
          isError && "text-rose-500"
        )}
      >
        App Componenets
      </h1>
    </>
  );
};
export default App;

3. CSS-in-JS

JavaScript의 기능을 CSS에 적용할 수 있고, 컴포넌트 기반의 스타일링을 하는 장점이 있는 기술이다.
 

CSS-in-JS 대표 기술

  • Styled Components
  • Emotion
  • Vanilla Extract (zero run time)
  • Linaria (zero run time)

Styled Components
기본적으로 scss 문법이 적용되고, 자바스크립트를 이용해 더 많은 기능을 만들어낼 수 있다.
하지만 JSX 상에서는 태그의 종류를 알 수가 없고(스타일 객체를 선언할때 태그를 작성하기 때문) 컴포넌트인지 스타일 객체인지 구분이 안된다는 단점이 있다.
styled-components 부분이 너무 길어지면 가독성이 안좋은데 현업에서는 어떻게 사용하는지 궁금해서 여쭤보았다.
현업에서는 따로 분리해서 사용한다고 알려주셨다!
 
분리하는 방법은 따로 찾아보았다.
예를 들어 원래는 Home.tsx 파일에 모든 styled-components 코드를 같이 작성되어있다면,
StyledHome.tsx 파일을 따로 만들어서 모든 스타일 객체를 이 파일에 옮기고, 이때 모든 변수 앞에 export를 붙여준다.
ex) export const Wrapper = styled.div`background-color: black;`;
그다음에 Home.tsx에서 스타일파일을 불러와준다.
import * as H from “../styled-components/StyledHome”;
그리고 JSX부분에 <H.Wrapper></H.Wrapper>처럼 사용하면 된다!
 
Emotion
Styled Components와 비슷한 방법이긴하지만, Styled Components에서는 태그를 컴포넌트로 만들지만,
Emotion은 class를 컴포넌트로 만든다.
그래서 JSX에서도 태그 이름을 확인할 수 있다!! 이거 진짜 편할 것 같다. 
Styled Components는 매번 스타일 객체 적은 부분 찾아야 태그를 알 수 있었는데 Emotion은 그럴 필요가 없는 게 너무 좋은 것 같다.
다음에는 Emotion을 사용해보고싶다.
그리고 Styled Components는 인터넷 익스플로러 11을 지원안했었는데, Emotion은 지원하는 장점이 있다고 하셨다.
 
Vanilla Extract
css도 별도의 연산작업이 필요하다. styled-components와 emotion도 많이 작성할수록 연산량도 증가한다.
그래서 zero run time이란게 등장했다. 빌드 타임에, 즉 사전에 연산을 다 끝내기 때문에 연산의 부담을 확 줄여서 성능을 개선해준다고 한다.
zero run time 중에서는 vanilla extract이 가장 인지도가 높다고 한다. 설치방법은 조작이 조금 더 필요한 편이다.
 

폰트 적용 방법

1. 구글 폰트

구글 폰트 페이지에서 폰트를 장바구니에 담고 get embeded를 클릭하면

이런 이미지가 나온다. 이대로 css 파일에 넣어주면 된다. (옵션은 굳이 안넣어도 된다.)

@import url("https://fonts.googleapis.com/css2?family=Bungee+Tint&family=Matemasie&display=swap");

.bungee-tint-regular {
  font-family: "Bungee Tint", sans-serif;
  font-weight: 400;
  font-style: normal;
}

.matemasie-regular {
  font-family: "Matemasie", sans-serif;
  font-weight: 400;
  font-style: normal;
}

 

2. 눈누 사이트

@font-face를 사용한다.

@font-face {
  font-family: "PTNoeulB";
  src: url("https://fastly.jsdelivr.net/gh/projectnoonnu/2408@1.0/PTNoeulB.woff2")
    format("woff2");
  font-weight: 700;
  font-style: normal;
}

.nunnufont {
  font-family: "PTNoeulB";
}

 

3. 그 외 폰트 사용

웹 폰트가 없고 ttf 파일만 있는 경우, woff와 woff2로 변환해주는 사이트에서 WOFF와 WOFF2파일을 생성하고,
src 하위에 assets 폴더를 생성해 넣어준다. 그리고 css 파일에 다음과 같이 작성해주면 된다.

@font-face {
  font-family: "JejuDoldam";
  src: url("../assets/jejudoldam.woff2") format("woff2"),
    url("../assets/jejudoldam.woff") format("woff");
}

.jejudoldam {
  font-family: "JejuDoldam";
}

 

컴포넌트 작성

기본 작성 방법은 이미 알고있었는데, 이벤트 핸들러 관련해서 자세히 설명해주셔서 다시 개념을 확립할 수 있는 시간이었다.

const App = () => {
  const onClickHandler = () => {
    console.log("버튼이 클릭되었습니다.");
  };
  return (
    <>
      <h1>App Component</h1>
      <button onClick={onClickHandler}>클릭</button>
      <button onClick={() => onClickHandler()}>클릭</button>
    </>
  );
};
export default App;

위의 코드에서 
(1) onClick={onClickHandler}
(2) onClick={() => onClickHandler()
이렇게 번호를 붙여보면, 2번은 매개변수가 존재할 때 사용하는 방식이다.
단, onClick={onClickHandler()} 이렇게는 쓰면 안된다! 이건 함수를 호출한 것이기 때문에 렌더링 되자마자 즉시 실행이 되어버린다.
그리고 매개변수가 없는데 2번으로 쓰는 건 안 좋은 방식이다.
 

const App = () => {
  const onClickHandler = (event) => {
    console.log(event);
  };
  return (
    <>
      <h1>App Component</h1>
      <button onClick={onClickHandler}>1번 버튼</button>
      <button onClick={() => onClickHandler()}>2번 버튼</button>
    </>
  );
};
export default App;

또 특이한 점은, event 객체와 관련해서이다.
onClick={onClickHandler}으로 작성하면, 내부에서 임의로 event 객체가 전달이 되기 때문에 위의 코드에서 1번 버튼을 클릭하면 event 객체가 콘솔에 출력된다.
하지만!! onClick={() => onClickHandler()}으로만 작성하면 event 객체가 전달이 안된다..!!
이런 방식에서 event객체를 전달하려면 onClick={(event) => onClickHandler(event)} 이렇게 명시를 해주어야 한다.
한 가지 팁은, 매개변수가 없이 event 객체만 필요한데 event 타입을 모르겠다면
먼저 onClick={(event) => onClickHandler(event)} 이렇게 작성한 후에 이 부분에 마우스를 올려보면

이렇게 타입을 알려준다!!(만세만세)
이걸 그대로 복사해서

const App = () => {
  const onClickHandler = (
    event: React.MouseEvent<HTMLButtonElement, MouseEvent>
  ) => {
    console.log(event);
  };
  return (
    <>
      <button onClick={onClickHandler}>클릭</button>
    </>
  );
};
export default App;

이렇게만 작성하면된다!
그동안 그냥 썼는데, 이제야 "알고" 쓰는 기분이다.ㅎㅎ
 

반응형