[React] Styled-components Naming
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>
);
};
단점
- html의 구조를 파악 어려움
- 공통 컴포넌트와 스타일 컴포넌트와의 구분 어려움
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>
);
};
단점
- props나 상태에 따라서 다른 스타일을 주기 위해서는 className 속성으로 조건문을 이용해 className을 선택적으로 지정해줘야 함
- className의 네이밍 어려움
- 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>
);
};
단점
- className의 네이밍 어려움
- SCSS 뎁스가 깊어져서 복잡함
- 공통 컴포넌트와 스타일 컴포넌트와의 구분 어려움
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;
}
`;
사실 어느 방식이 좋은 건지는 잘 모르겠다. 이렇게 정형화가 되어있지 않은 걸 보면 취향껏 사용하는 것 같기는 한데 최대한 깔끔하게 짜고 싶은 마음이 있다 보니 계속 고민하게 된다. 이 방식, 저 방식 사용해보면서 본인에게 제일 잘 맞는 방식을 선택하는 게 제일 베스트인 것 같다.