[React 완벽 가이드] Section 5 & Section 6 : 실습 + Styling

gonn-i·2024년 6월 3일
0

React 완벽 가이드

목록 보기
4/18
post-thumbnail

본 포스트는 Udemy 리액트 완벽가이드 2024 를 듣고 정리한 내용입니다.

Section 5

Investment Calculator 실습

실습 code 📁

Section 6

styling

목차 🌳
1️⃣ Vinilla CSS 로 스타일링
2️⃣ CSS Modules를 통한 스코핑
3️⃣ Styled Components 사용하기
4️⃣ Tailwind CSS 로 스타일링
5️⃣ 정적, 동적으로 CSS 적용하기

Vanilla CSS

vite를 통한 웹 번들링을 거치면, js로 css 파일을 import 할 수 있음.
vite는 import를 식별하고 css 파일이 내부에 주입됨

장점
1️⃣ CSS 를 담당하는 사람이 있어 분없이 가능하다면, 파일만 import 해주면 되기 때문에 간결하며, JSX 코드에 접근 및 수정을 최소화함.
2️⃣ 흔히 아는, CSS 코드를 사용할 수 있음

단점
1️⃣ CSS 규칙은 컴포넌트로 스코핑되어 있지 않음 (한 컴포넌트로 CSS 적용 범위가 정해져 있지 않음)
-> 다른 컴포넌트 간에 내부 className이 같을 경우, 스타일 충돌이 이루어질 수 있다.

Header.jsx

import logo from '../assets/logo.png';
import './Header.css';
export default function Header() {
  return (
    <header>
		...
    </header>
  );

헤더에만 Header.css 를 import 한 경우에도, 그 파일에 CSS 규칙들은 Header에만 적용되지 않는다.

(하나의 컴포넌트에 대해서만 스코핑 적용 ❌)
클래스 선택자 혹은 html 태그가 전역 범위에 정의되어, 충돌이 일어날 수 있다💥 import 하지 않은 jsx 파일의 코드에도 적용이 된다는 말

ClassName을 통해 동적으로, 스타일 부여하기

<label className={`${emailNotValid ? 'invalid' : ''}`}>Email</label>

inline style

컴포넌트에 CSS를 스코핑 하기 위한 방법 중 하나로,
css 파일에 style을 적는 것이 아닌 ➡️ jsx 파일 내부에, 태그 안에 속성값으로 style={{color: 'red'}} 와 같이 넣어주는 방법

이때, inline 스타일을 정의할 때는, {{}} 이중 중괄호를 사용하게 되는데,
그냥 key-value 형태의 스타일 값을 동적으로 할당해줘야 하기 때문에 중괄호가 두개 필요하구나~ 생각하면 되겠다. key-value에서 { } , 동적 할당으로 인해 { }

  • key값인 스타일 속성은 카멜케이스로 작성!
export default function Header() {
  return (
    <header>
      <p style={{
          color: 'red',
          textAlign: 'center'
        }}>A community of artists and art-lovers.</p>
    </header>
  );
}

장점
1️⃣ 원하는 요소에만 스타일을 적용할 수 있다. (다른 요소에 적용 ❌ )
2️⃣ 동적 스타일링이 용이함

inline 동적 스타일링 예시

export default function AuthInputs() {
  const emailNotValid = submitted && !enteredEmail.includes('@');
	return (
      <input
        type="email"
        style={{
          backgroundColor: emailNotValid ? '#fed2d2' : '#d1d5db',
        }}
        />
    )
}

단점
1️⃣ 모든 요소를 개별적으로 다 스타일 적용해야 한다는 점, 무수한 중복 발생
-> 공통적으로 적용될 수 있는 스타일도 다 따로 작성해줘야 함 (수정도 마찬가지)
2️⃣ CSS 코드 JSX 코드에 구분이 없음
-> 가독성, 협업 bad


CSS Module

Vanilla css로 작성하되, 스코프도 지정할 수 있는 방법
방법
1️⃣ 파일이름: Header.css ➡️ Header.module.css으로 변경
2️⃣ import 하여 객체의 이름을 네이밍 해줘야 함
-> ex) import classes from ./Header.module.css
3️⃣ className으로 사용시, import한 곳에서의 class에 접근
-> <p className={classes.paragraph}></p>

className 이 겹치더라도 빌드 과정에서 import 한 컴포넌트의 파일로 스코핑되도록 보장함!

장점
1️⃣ CSS 를 담당하는 사람이 있어 분없이 가능하다면, 파일만 import 해주면 되기 때문에 간결하며, JSX 코드에 접근 및 수정을 최소화함.
2️⃣ 흔히 아는, CSS 코드를 사용할 수 있음
3️⃣ import된 컴포넌트로 스코프되어, className이 겹쳐도 충돌되지 않음!

단점
1️⃣ 많은 css 파일을 만들어야 할 수 있음, 한 컴포넌트에 하나씩 타켓팅하면 (내부 양은 적지만, 파일 수는 많은 .. )
2️⃣ CSS 코드 JSX 코드에 구분이 없음
-> 가독성, 협업 bad


styled-components 💅

말그대로, CSS를 컴포넌트화 시켜주는 라이브러리

사용방법
1️⃣ styled-components 패키지에서 import 해주기
import { styled } from 'styled-components'
2️⃣ styled 객체에 알맞는 html 태그 속성을 넣어주고 (styled.div), 백틱(tagged-template)으로 스타일 감싸주기

const 변수 = styled.html요소`
	  css 속성: css 내용,
	  css 속성: css 내용,
	  ...
`

ex styled-component

const ControlContainer = styled.div`
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
`;

동적 스타일링 방법? 🤨

예 물론 있죠.
css 클래스를 따로 추가 하지 않고도, props를 추가적으로 만들어조건에 따라서 스타일을 부여할 수 있다 ! (styled components 도 컴포넌트이니까~)
props 넘겨주는 방법 예시

<Label $invalid={emailNotValid}>Email</Label>

props-> $invalid에 따라서 true 혹은 false가 설정.

const Label = styled.label`
  ...
  color: ${({ $invalid }) => ($invalid ? '#f87171' : '#6b7280')};
`;

styled components인 Label에서, 백틱으로 감싸진 ${ ... } 화살표 함수를 작성하고, 그 안에 인자인 props의 상태에 따라 조건에 맞는 스타일 값을 동적으로 출력하게 된다.

근데 왜 styled component에서 사용하는 props에는 $를 붙여서 쓰나요? 🤨

왜냐면, styled component로 전달되는 propsHTML 내장 속성 간의 충돌을 피하기 위해서 !
일부 props 가 HTML 속성으로 직접 전달되어 예상치 못한 동작을 발생시킬 수 있기 때문
따라서, $를 붙여서 HTML 표준 속성과 충돌하지 않도록 관례로 정해졌다.

html 표준 속성 예시

<input type="checkbox" checked> // checked
<input type="text" required> //required
<form action="/submit" method="post"> // action 
  <input type="text" name="username"> //type name 등등
  <button type="submit">Submit</button>
</form>
  

media 쿼리, 중첩규칙, 가상 선택자

중첩 규칙 + 반응형 (미디어쿼리)

<header>
  <img src={logo} alt="A canvas" />
  <h1>ReactArt</h1>
  <p>A community of artists and art-lovers.</p>
<header>    

❌ 헤더 태그 내부에 위치하고 있는 요소들에 대해 각각 컴포넌트를 만들어, 스타일을 적용시키는 것이 아닌!
헤더에 대한 styled components 내부에 & 적용할 요소 와 같이 작성해주면 된다.

ex) nested styled components

const StyledHeader = styled.header`
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin-top: 2rem;
  margin-bottom: 2rem;

  & img {
    object-fit: contain;
    margin-bottom: 2rem;
    width: 11rem;
    height: 11rem;
  }

  @media (min-width: 768px) {
    & {
      margin-bottom: 4rem;
    }

    & h1 {
      font-size: 2.25rem;
    }
  }
`;

단, 부모요소 -> 자식에 대한 스타일 작성은 &(한칸공백)요소 로 작성해야 한다.
&p
⭕️& p⭕️

이처럼 styled components 사용시, 자식요소에 대한 style 추가(중첩)와, 미디어 쿼리 적용간단하다!

가상 선택자 (pseudo 선택자)

자식 요소에 대한 style 적용과 유사하되, &공백 없이 가상선택자를 적어주면 된다.

const Button = styled.button`
  padding: 1rem 2rem;
  font-weight: 600;
  ...

  &:hover {
    background-color: #f0920e;
  }
`;

장점
1️⃣ 리액트 컴포넌트 단위에서 생각하면 되기 때문에, 간단
2️⃣ 스타일이 필요한 컴포넌트로 스코핑 되기 때문에, css 충돌이 없음

단점
1️⃣ 상대적으로 많은 컴포넌트가 생겨날 수 있음 (작고, 그 수가 많아서, 헷갈릴 수 있음)
2️⃣ jsx와 css의 영역이 명확하게 구분되지 않음

-> 재사용되는 스타일 컴포넌트는 따로 관리하는게 맞음
(결국 스타일 컴포넌트도 리액트의 컴포넌트의 관점에서 생각하기)

Tailwind CSS

스타일 라이브러리 html 요소에 유틸리티 클래스를 적용하여, css를 그려냄
css 프레임워크

Vite 환경에서 Tailwind CSS 설치 및 설정 방법

export default function Header() {
  return (
    <header className="flex flex-col items-center mt-8 mb-16">
      <img src={logo} alt="A canvas" className="object-contain mb-8 w-44 h-44" />
      <h1 className="text-4xl font-semibold tracking-widest text-center uppercase text-amber-800">
        ReactArt
      </h1>
    </header>
  );
}

이런식으로 bootstrap 쓰듯이 사용하면 된다.
더 많은 내용은 공식문서 참조
ex Flex 적용 방식

내가 원하는 스타일이 없으면 어쩌죠? Custom 하면 되죠~

index.css

@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  background-color: #ffaa00;
  background-image: url("data:image/svg+xml");
  background-attachment: fixed;
  background-size: cover;
}

Tailwind 지시어 추가해주고, 메인 스타일 파일에 css 로 만들어주기

  • 폰트를 추가하고 싶다면 어떻게 하나요? 🧐

tailwind.config.js

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

extend 부분에 폰트 추가해주기,
이때 title은 새롭게 추가하고 싶은 폰트의 새로운 이름일 뿐임
(구글에서 불러온 폰트는 이중따옴표로 한번더 감싸주기!)

반응형 관련 문서
가상자 관련 문서

장점
1️⃣ CSS 를 잘 몰라도 쓸 수 있음
2️⃣ 다 만들어진 css를 사용하는거라 개발 속도가 더 빠르다고 함
3️⃣ 스타일 충돌이 없음

단점
1️⃣ 클래스가 너무 길어진다.
2️⃣ tailwind 만으로 끝나는게 아니라, 추가로 css 작업이 필요하기도 함
3️⃣ jsx와 css 코드 사이에 구분이 명확하지 않음
4️⃣ 내용의 양이 작고 또 그 수가 많은 wrapper 컴포넌트가 생김 (코드줄이 늘어남)

0개의 댓글