Styled-components란?

  • Javascript 파일 내에서 CSS를 사용할 수 있게 해주는 대표적인 CSS-in-JS 라이브러리로 React 프레임워크를 주요 대상으로 한 라이브러리
  • 기존 돔을 만드는 방식인 css, scss 파일을 밖에 두고 태그나 id, class이름으로 가져와 쓰지 않고 컴포넌트 이름을 쓰듯 스타일을 지정하는 방식
  • css 파일을 밖에 두지 않고 컴포넌트 내부에 넣기 때문에 css가 전역으로 중첩되지 않도록 만들어주는 장점이 있음
  • Styled 컴포넌트를 만들어 전달받은 props를 이용해 선택적으로 css를 사용할 수 있음

 

글 작성 이유

className에 대한 고민이나, BEM 사용법이 맞는지 등.. 고민을 안 하게 되어서 좋았지만 styled-component의 이름을 어떻게 지어야 할지에 대한 고민이 생겼다. 다른 사람들의 코드를 참고해봐도 네이밍 방식이 제각각이라서 고민이 더 깊어졌고, 그 방식들 중 그래도 자주 보이는 몇 가지와 검색을 통해 알게 된 방식들을 정리하려고 한다. 

 

Component 네이밍

컴포넌트에 특정 기능에 맞는 이름을 넣어 모든 태그에 네이밍을 해주는 방식

const MainPage = () => {
  return (
    <MainPageLayout>
      <Header>
        <HeaderTitle>메인 페이지</HeaderTitle>
        <HeaderNav>
          <HeaderNavList>
            // active속성을 props로 전달해서 css를 설정
            <HeaderNavItem active>홈</HeaderNavItem>
            <HeaderNavItem>메뉴1</HeaderNavItem>
            <HeaderNavItem>메뉴2</HeaderNavItem>
          </HeaderNavList>
        </HeaderNav>
      </Header>
      <Content>
        <SlideContent>
          <ContentItem>1</ContentItem>
          <ContentItem>2</ContentItem>
          <ContentItem>3</ContentItem>
        </SlideContent>
      </Content>
      <Footer>하단 내용</Footer>
    </MainPageLayout>
  );
};

단점

  1. html의 구조를 파악 어려움
  2. 공통 컴포넌트와 스타일 컴포넌트와의 구분 어려움

 

ClssName 네이밍

 가장 상위의 태그만 스타일 컴포넌트로 만들어주고 안에 있는 태그들에는 className을 이용해서 네이밍 해주는 방식

const MainPage = () => {
  return (
    <MainPageLayout>
      <header className="header">
        <h2 className="header__title">메인 페이지</h2>
        <nav className="nav">
          <ul claName="nav__list">
            // 특정 조건일때는 className에 --active를 붙여주도록 코드를 작성해야함
            <li className="nav__item nav__item--active">홈</li>
            <li className="nav__item">메뉴1</li>
            <li className="nav__item">메뉴2</li>
          </ul>
        </nav>
      </header>
      <div className="content">
        <SlideContent className="content__list">
          <li className="content__item">1</li>
          <li className="content__item">2</li>
          <li className="content__item">3</li>
        </SlideContent>
      </div>
      <footer className="footer">하단 내용</footer>
    </MainPageLayout>
  );
};

단점

  1. props나 상태에 따라서 다른 스타일을 주기 위해서는 className 속성으로 조건문을 이용해 className을 선택적으로 지정해줘야 함
  2. className의 네이밍 어려움
  3. SCSS 뎁스가 깊어져서 복잡함

 

혼합 네이밍

위의 두 방식을 혼합한 방식으로 스타일만 가지고있는 태그들은 className을 이용해 네이밍 하고, 상태를 가지고 있는 태그들은 스타일 컴포넌트를 이용해 네이밍 하는 방식

const MainPage = () => {
  return (
    <MainPageLayout>
      <header className="header">
        <h2 className="header__title">메인 페이지</h2>
        <nav className="nav">
          <ul claName="nav__list">
            // 상태값을 가지는 태그는 스타일 컴포넌트로 분리
            <NavItem active>홈</NavItem>
            <NavItem>메뉴1</NavItem>
            <NavItem>메뉴2</NavItem>
          </ul>
        </nav>
      </header>
      <div className="content">
        <SlideContent className="content__list">
          <li className="content__item">1</li>
          <li className="content__item">2</li>
          <li className="content__item">3</li>
        </SlideContent>
      </div>
      <footer className="footer">하단 내용</footer>
    </MainPageLayout>
  );
};

단점

  1. className의 네이밍 어려움
  2. SCSS 뎁스가 깊어져서 복잡함
  3. 공통 컴포넌트와 스타일 컴포넌트와의 구분 어려움

 

S-dot 네이밍

스타일 컴포넌트를 분리할때 S라는 이름으로 요약하여 구분해주는 방식
스타일 파일을 분리해서 스타일들을 내보낼 때 객체에 담아서 내보내고, 사용할 파일에서 모든 요소들을 S라는 이름으로 묶어서 불러와 사용

import * as S from ./styles.js;

const MainPage = () => {
	return (
    <S.MainPageLayout>
      <S.Header>
      	<S.HeaderTitle>메인 페이지</HeaderTitle>
      	<S.HeaderNav>
      		<S.HeaderNavList>
      			// active속성을 props로 전달해서 css를 설정
      			<S.HeaderNavItem active>홈</S.HeaderNavItem>
      			<S.HeaderNavItem>메뉴1</S.HeaderNavItem>
      			<S.HeaderNavItem>메뉴2</S.HeaderNavItem>
      		</S.HeaderNavList>
      	</S.HeaderNav>
      </S.Header>
      <S.Content>
      	<SlideContent>
      		<ContentItem>1</S.ContentItem>
      		<ContentItem>2</S.ContentItem>
      		<ContentItem>3</S.ContentItem>
    		</SlideContent>
  		</S.Content>
  		<S.Footer>
  			하단 내용
  		</S.Footer>
   	</S.MainPageLayout>
 )
}

방식을 정했다면 이제 컴포넌트명을 어떻게 지을지에 대한 고민이 남는다.

검색을 하다 아래와 같은 컨벤션을 찾았다. 

 

최상위 컴포넌트 명

  • '컴포넌트명'Layout

각 태그들의 컴포넌트 명

  • div : '컴포넌트명'Box
  • section : '컴포넌트명'Section
  • ul : '컴포넌트명'List
  • li : '컴포넌트명'Item
  • p : '컴포넌트명'Paragraph
  • span : '컴포넌트명'Span

컴포넌트들을 묶어주는 컴포넌트 명

  • '컴포넌트명'Row/Col

이 컨벤션을 사용한다면 html 구조 파악에 대한 어려움은 줄일 수 있을 것 같다. 

 

또 다른 방식으로는 Styled나  St를 앞에 붙여서 <StyledWrapper>처럼 스타일 컴포넌트와 공통 컴포넌트의 구분을 편리하게 해주는 방식이 있다.

다만 이러한 방식을 지양하라고 하는 말도 있었는데 이유까지는 나와있지 않았다. 

  • Styled'컴포넌트명': 앞에 Styled 사용을 지양할 것
  • ~Wrapper: div태그 같은것에는 사용하지만 이 대신 Box라는 이름을 사용한다.

 


 

나 같은 경우는 혼합 네이밍을 사용하되 depth가 너무 깊어지지 않고, 꼭 필요한 경우가 아니라면 className을 붙이지 않고 중첩 구문을 사용하려고 하고 있다. 그리고 컴포넌트명은 '컴포넌트명'을 앞에 붙이고 있다. 

function Modal({ hidden, hideModal, modalInfo }) {
  return (
    <>
      {!hidden && (
        <>
          <ModalBackground onClick={hideModal} />
          <ModalItem>
            <h1>비밀번호를 입력하세요</h1>
            <p>{modalInfo.hint}</p>
            <input
              type="text"
              onChange={(e) => {
                console.log(e.target.value);
              }}
            />
          </ModalItem>
        </>
      )}
    </>
  );
}

...

const ModalItem = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;

  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);

  width: 500px;
  height: 210px;
  padding: 30px;
  background: ${({ theme }) => theme.color.ghostwhite};
  border-radius: 25px;
  z-index: 2;

  h1 {
    font-family: ${({ theme }) => theme.font.title};
    font-weight: bold;
    font-size: 30px;
    color: ${({ theme }) => theme.color.purple};
  }

  p {
    font-family: ${({ theme }) => theme.font.content};
    font-size: 20px;
  }

  input {
    width: 400px;
    height: 50px;

    padding-left: 15px;
    border: 3px solid ${({ theme }) => theme.color.purple};
    border-radius: 10px;

    text-align: center;
    font-family: ${({ theme }) => theme.font.content};
    font-size: 25px;
  }
`;

사실 어느 방식이 좋은 건지는 잘 모르겠다. 이렇게 정형화가 되어있지 않은 걸 보면 취향껏 사용하는 것 같기는 한데 최대한 깔끔하게 짜고 싶은 마음이 있다 보니 계속 고민하게 된다. 이 방식, 저 방식 사용해보면서 본인에게 제일 잘 맞는 방식을 선택하는 게 제일 베스트인 것 같다. 

 

'프로그래밍 > React' 카테고리의 다른 글

[React Query] 리액트 쿼리 이해하기  (3) 2022.08.22
[React] Link와 useNavigate  (0) 2022.06.23
[React] useRef  (0) 2022.05.08
[React] 이벤트 핸들링  (0) 2022.04.19
[React] component, props, state  (0) 2022.03.09
복사했습니다!