배워서 남 주자

반응형 웹 디자인을 적용한 화면을 styled-components로 리팩토링하기

미래에서 온 개발자 2023. 1. 20. 21:26

지난 포스팅에서 pocket을 클론해 반응형 웹을 구현한 코드를 styled-components로 리팩토링 해보았다. 통번역 대학원 다닐 때도 시역(sight translation, 텍스트를 눈으로 읽어나가면서 입으로 소리내어 통역하는 훈련)했던 텍스트로 통역해보고 번역해보고, 정말 좋은 텍스트라면 암기하는 등 이것저것 여러 텍스트를 마구잡이로 다 보는 것보다 좋은 텍스트를 하나 정해서 여러 가지를 해보는 게 실력 증진에 더 큰 도움이 되었다. 부트캠프에서도 기본적으로는 매일매일 해야 할 과제가 다르지만 vanilla js로 작성한 코드를 리액트로 바꿔본다든지, react에서 state를 관리하는 방식으로 구현했던 과제를 가지고 똑같은 리액트 코드에서 state 관리만 redux를 적용해 본다든지 하는 방식으로 주어지는 과제들을 하면서 학습에 큰 도움이 되었다.

기존 코드에서는 react.module.css 방식으로 코드를 작성했는데, styled-components로 리팩토링을 해보니 css 파일을 싹 다 날려버릴 수 있었다. 과연 css-in-js 방식을 직접 써보니 하나의 컴포넌트 파일(.js)에서 html, css, js를 한번에 파악할 수 있는 게 특장점이라고 할 수 있다.

기본적으로 styled-components를 설치해준 다음, css 파일을 import 해오던 컴포넌트마다 styled-components를 불러와서 styled-components를 만들어주고 그 안에 기존 css 코드를 그대로 복사해 오면 됐다. 이번 포스팅에서는 리팩토링 과정에서 새로 알게 된 점 몇 가지만 정리해 본다.


1. css reset 코드는 어디에 써줘야 하는가?
createGlobalStyle 함수를 불러와서 전역 스타일을 설정해 줄 수 있다. 그 다음 최상위 컴포넌트에서 <GlobalStyle> 컴포넌트를 사용하면 전역에 리셋 스타일이 적용된다.

import { createGlobalStyle } from "styled-components";

const GlobalStyle = createGlobalStyle`
	// css reset code here
`

function App() {
  return (
    <>
      <GlobalStyle />
      <Header />
      <Main />
    </>
  );
}

export default App;


이때, <GlobalStyle></GlobalStyle>처럼 열고 닫는 방식으로 다른 컴포넌트들을 감싸주면 콘솔 창에 다음과 같은 경고 문구가 뜨고, 화면이 전부 하얘지면서 리액트 컴포넌트가 렌더링되지 않으니 주의해야 한다.

콘솔 경고 메시지


찾아보니 스타일 컴포넌트에서 제공하는 reset 패키지도 있다고 한다. styled-reset을 설치해서 다음과 같이 사용하면 된다고 하는데, 이번 실습에서 초기화해줄 css 코드가 많지 않아서 따로 설치해서 사용하지는 않았다.

import reset from 'styled-reset';

const GlobalStyles = createGlobalStyle` 
  ${reset} 
`


2. media query 적용
미디어 쿼리도 별 거 없다. 그냥 스타일드 컴포넌트 안에 그대로 써주면 된다.

기존 css 코드 작성을 아래와 같이 했다면,



styled-components로 리팩토링을 할 때는 다음과 같이 해주면 된다. 코드 맨 윗줄에 import로 리액트, styled-components 등을 불러와야 하는 부분은 생략했다.



미디어 쿼리로 분기를 줄 때 스타일 컴포넌트의 자식 요소에 대한 스타일을 변경해야 하는 경우는 다음과 같이 자식 선택자(>)를 써줬다. 기본적인 css와 다른 부분이 크게 없다고 보면 된다. sass처럼 &을 쓸 수 있다는 것 정도인데, 이건 꼭 미디어 쿼리 안에서만 쓸 수 있는 게 아니라 스타일 컴포넌트 안에서 어디서나 다 쓸 수 있다.

const MainContainer = styled.main`
  padding: 40px;
  padding-top: 64px;
  margin: 0 auto;
  max-width: 1128px;
  @media screen and (max-width: 720px) {
    & > h1 {
      font-size: 1.4rem;
    }
    & > h2 {
      font-size: 1rem;
      font-weight: 500;
    }
  }
`;

function Main() {
  return (
    <MainContainer>
      <h1>최고의 웹 컨텐츠 검색</h1>
      <h2>오늘의 필독 자료</h2>
      <Top />
      <hr />
    </MainContainer>
  );
}



3. props로 조건부 렌더링
기존 css를 작성했을 때는 아티클 정보 중에 main 아티클인지 여부를 true, false 등 boolean 값을 갖게 해서 props로 내려받은 아티클 정보를 가지고 class 이름을 mainItem, item으로 다르게 설정해주었다.

스타일 컴포넌트에서는 이 main에 담겨있는 불리언 값을 props로 활용해서 item의 grid-rows와 grid-columns를 아래와 같이 설정해줄 수 있었다. 이때 grid-rows 값 span 2 등을 ""로 묶어주지 않으면 삼항 연산자의 :를 읽지 못하는 syntaxError가 떴다. 확실치는 않지만 추정하기로는 props로 받는 것도 일종의 변수 설정이라고 볼 수 있는데, 변수로 css 속성값을 줄 때에는 ""로 묶어서 string으로 처리해줘야 스타일 컴포넌트가 작동하는 것 같다.



4. html 엘리먼트의 속성을 styled-components에 추가하기
리팩토링 중 의외로 가장 난관을 겪었던 부분이다.

화면 구성에서 기본 컴포넌트 역할을 하는 아티클 카드 컴포넌트에서 <img> 태그의 src 값이 아티클 데이터 중에 imgUrl에 담겨 있었다. 그리고 이 이미지 태그의 스타일링을 위해 width 값 지정과 border-radius를 준 상황이었다.

import styles from "../styles/Card.module.css";

function Card({ data }) {
  const { imgUrl, title, source, readtime, excerpt, main } = data;

  return (
   	// 생략
        <div className={styles.media}>
            <img src={imgUrl}></img>
        </div>
	// 생략
  );
}

// css code
.media img {
    width: 100%;
    border-radius: 0.8rem;
}


일단 html 태그의 속성을 스타일 컴포넌트로 가져오는 방법을 검색해보니 .attrs() 메소드로 속성을 추가해줄 수 있었다. 기본적인 syntax는 메소드의 전달인자로 html 요소의 속성을 지정해 객체로 전달해 주면 된다.

const Input = styled.input.attrs({ required: true })`
	// css code here
`;


여러 속성을 한꺼번에 전달할 수도 있으며, props를 속성값으로 지정할 수도 있다.

const MediaImg = styled.img.attrs((props) => ({ src: props.imgUrl }))`
  width: 100%;
  border-radius: 0.8rem;
`;

function Card({ data }) {
  const { imgUrl, title, source, readtime, excerpt, main } = data;

  return (
	//생략
        <div className="media">
            <MediaImg imgUrl={imgUrl}></MediaImg>
        </div>
	//생략
  );
}


이때 객체를 화살표 함수의 리턴값으로 작성하게 되기 때문에 이렇게 attrs(props => { src: props.imgUrl }) 코드를 적으면 컴파일 에러가 난다. 그 이유에 대해서는 전에 이미 같은 유형의 에러를 만난 적이 있어서 간단하게 작성해둔 포스팅으로 갈음한다.

 

 

[2023. 2. 4. 추가] 

styled-components로 정의한 컴포넌트도 그저 하나의 컴포넌트라는 사실을 간과하고 너무 어렵게 생각했다. attrs() 메소드 없이 컴포넌트에 그대로 속성을 설정해주는 편이 더 간편하다. 

// attrs() 메소드 삭제
const MediaImg = styled.img`
  width: 100%;
  border-radius: 0.8rem;
`;

function Card({ data }) {
  const { imgUrl, title, source, readtime, excerpt, main } = data;

  return (
	// 생략
            <MediaImg src={imgUrl}></MediaImg>
  );
}



📚 참고자료

 

styled-components attrs()에 대하여

프로젝트에서 .attrs()을 사용하는 것을 보았는데 이름에서 대충 attributes를 받아다 쓰는 건가보다 싶었다그래서 좀 더 구체적인 사용법을 알아보기로 하였다⚠ 회사에서 모르는 내용이나 미흡한

velog.io

 

React - Styled Components 사용 방법

React에는 여러 방법을 통해 CSS를 적용할 수 있다. 그 중에서도 개인적으로 가장 좋다고 생각되는 Styled-Components의 여러 사용 방법에 대해 알아보자.

velog.io