Styled Component

be kid·2022년 2월 5일
0

BEB - 웹 개발 과정

목록 보기
23/28

같은 UI 컴포넌트를 공유하고 재사용할 수 있도록 부품 단위로 UI 컴포넌트를 만들어 나가는 개발 방법인 Component Driven Development (CDD)와 그를 위한 도구 Storybook에 대해 배웠다.
Storybook은 UI를 개발할 때 직접 웹을 띄워놓고 이동하며 확인해보지 않아도 작성된 컴포넌트들을 각각 확인할 수 있도록 해준다. 만들어진, 수정된 UI를 확인하기 위해 해당 페이지까지 직접 이동하지 않아도 된다는 말이다.

CSS in JS 방법론

프로젝트와 팀의 규모가 커지면서 CSS를 작성하는 일관된 패턴이 없는 것은 개발자들에게 큰 걸림돌이 되었고, 모바일, 태블릿 등 다양한 디바이스의 등장으로 웹사이트들이 다양한 디스플레이를 커버해야 하기 때문에 CSS는 더 복잡해지게 되었다.
CSS 작업을 효율적으로 하기 위해 구조화된 CSS의 필요성이 대두되었고 연구가 필요해졌다.

CSS 문서를 작성할 때의 번거로운 작업이나 클래스 상속과 같은 사항으로 문서의 양이 많아지고 유지관리에 영향이 생기는 것을 프로그래밍 개념(변수, 함수, 상속 등)을 활용하여 해결하기 위해 CSS 전처리기라는 개념이 등장했다. 하지만 이것 자체만으로는 웹서버가 인지하지 못해 그에 맞는 컴파일러를 사용해야 했다.
그래도 이를 통해 CSS 파일들을 구조화할 수 있게 되었고, 최소한 CSS 파일을 몇 개의 작은 파일로 분리할 수 있는 방법이 생겼다.

SASS

CSS 전처리기 중에서 가장 유명한 SASS(Syntactically Awesome Style Sheets)는 CSS를 확장해주는 스크립팅 언어. 즉, CSS를 만들어주는 언어로서 자바스크립트처럼 특정 속성(ex. color, margin, width 등)의 값(ex. #ffffff, 25rem, 100px 등)을 변수로 선언하여 필요한 곳에 선언된 변수를 적용할 수도 있고, 반복되는 코드를 한번의 선언으로 여러 곳에서 재사용할 수 있도록 해 주는 등의 기능을 가졌다.

SASS는 SCSS코드를 읽어서 전처리한 다음 컴파일해서 전역 CSS 번들 파일을 만들어주는 전처리기의 역할.

하지만 얼마 지나지 않아 SASS가 CSS의 구조화를 해결해 주는 것의 장점보다 다른 문제들을 더 많이 만들어낸다는 것이 밝혀짐. → 결국 우리는 전처리기가 내부에서 어떤 작업을 하는지 알지 못한 채, 스타일이 겹치는 문제를 해결하기 위해 단순히 계층 구조를 만들어 내는 것에 의지하게 되었고, 그 결과 컴파일된 CSS의 용량은 어마어마하게 커지게 되었음.

CSS 방법론의 대두

이러한 CSS 전처리기의 문제를 보완하기 위해 BEM, OOCSS, SMACSS 같은 CSS 방법론이 대두되었음. 각각의 장단점이 있으나 결국 세 방법론 모두 같은 지향점을 가지고 있음.

방법론의 공통 지향점은 다음과 같다.

  • 코드의 재사용
  • 코드의 간결화(유지 보수 용이)
  • 코드의 확장성
  • 코드의 예측성(클래스 명으로 의미 예측)

BEM

Block, Element, Modifier로 구분하여 클래스명을 작성하는 방법, Block, Element, Modifier 각각은 --와 __ 로 구분한다. 클래스명은 BEM 방식의 이름을 여러번 반복하여 재사용할 수 있도록하며 HTML/CSS/SASS 파일에서도 더 일관된 코딩 구조를 만들어 준다.

하지만 이러한 방법론들에서도 문제점은 있었다. 클래스명 선택자가 장황해지고, 이런 긴 클래스명 때문에 마크업이 불필요하게 커지며, 재사용하려고 할 때마다 모든 UI 컴포넌트를 명시적으로 확장해야만 했다.

또한 SASS와 BEM도 고치지 못했던 몇 가지 문제들은 언어 로직 상에 진정한 캡슐화(encapsulation : 객체의 속성과 행위를 하나로 묶고 실제 구현 내용 일부를 외부에 감추어 은닉하는 개념)의 개념이 없다는 것이었고, 이로 인해 개발자들이 유일한 클래스명을 선택하는 것에 의존할 수밖에 없었다.

CSS-in-JS의 등장 - Styled-Component

앱으로 개발 방향이 진화하면서 컴포넌트 단위의 개발은 캡슐화의 중요성을 불러왔다. 하지만 CSS는 컴포넌트 기반의 방식을 위해 만들어진 적이 한 번도 없었고 CSS도 컴포넌트 영역으로 불러들이기 위해서 CSS-in-JS가 탄생해 이 문제를 해결한다.

대표적인 CSS-in-JS인 Styled-Component

기능적(Functional) 혹은 상태를 가진 컴포넌트들로부터 UI를 완전히 분리해 사용할 수 있는 아주 단순한 패턴을 제공한다.

컴포넌트 기반 CSS 작성에 적합한 Styled-Component

React의 컴포넌트 기반 개발 환경에서 스타일링을 위한 CSS의 성능 향상을 위해 탄생함.
기존 CSS 문법으로도 스타일 속성이 추가된 React 컴포넌트를 만들 수 있음.
만약 버튼을 하나 만든다면 JavaScript에서 변수를 선언하듯이(혹은 React에서 컴포넌트를 만들듯이) Button을 만들고, tag의 속성을 정의하고, back-ticks안에 기존 CSS 문법을 이용하여 스타일 속성을 정의해 준다.

const Button = styled.a`
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
`;

Styled Component의 특징

  • Automatic critical CSS
    Styled Component는 화면에 어떤 컴포넌트가 렌더링 되었는지 추적해서 해당하는 컴포넌트에 대한 스타일을 자동으로 삽입함. 따라서 코드를 적절히 분배해 놓으면 사용자가 어플리케이션을 사용할 때 최소한의 코드만으로 화면이 띄워지도록 할 수 있음.
  • No class name bugs
    Styled Component는 스스로 유니크한 className을 생성함. 이는 className의 중복이나 오타로 인한 버그를 줄여줌.
  • Easier deletion of CSS
    기존에는 더 이상 사용하지 않거나 삭제한 컴포넌트에 해당하는 스타일 속성을 제거하기위해 CSS 파일 안의 className을 직접 찾아야 했다. 하지만 Styled Component는 모든 스타일 속성이 특정 컴포넌트와 연결되어 있기 때문에 만약 컴포넌트를 더 이상 사용하지 않아 삭제할 경우 이에 대한 스타일 속성도 함께 삭제됨.
  • Simple dynamic styling
    className을 일일이 수동으로 관리할 필요 없이 React의 props나 전역 속성을 기반으로 컴포넌트에 스타일 속성을 부여하기 때문에 간단하고 직관적임
  • Painless maintenance
    컴포넌트에 스타일을 상속하는 속성을 찾아 다른 CSS파일들을 검색하지 않아도 되기 때문에 코드의 크기가 커지더라도 유지보수가 어렵지 않음.
  • Automaic vendor prefixing
    개별 컴포넌트마다 기존의 CSS를 이용하여 스타일 속성을 정의하면 됨. 이외의 것들은 Styled Component가 알아서 처리해줌
# with npm
$ npm install --save styled-components

# with yarn
$ yarn add styled-components

아래 코드를 package.json에 추가하면 여러 버전의 Styled Component가 설치되어 발생하는 문제를 줄여줌.

{
  "resolutions": {
    "styled-components": "^5"
  }
}

Adapting based on props & Extending Styles

스타일 속성을 지닌 컴포넌트를 정의할 때에 함수를 전달하고, 그 함수 안에서 props를 사용할 수도 있다.

// Button component
...
  background: ${(props) => (props.primary ? "palevioletred" : "white")};
  color: ${(props) => (props.primary ? "white" : "palevioletred")};
...

// App component
...
  <Button>Normal</Button><Button primary>Primary</Button>

아래는 상속 예시

// 기존의 Button 컴포넌트에 Tomato 컴포넌트만을 위한 새로운 속성 추가
const Tomato = styled(Button)`
  color: tomato;
  border-color: tomato;
`;

useRef

DOM 엘리먼트의 주소값을 활용해야 하는 경우 useReffh DOM 노드, 엘리먼트, 그리고 리액트 컴포넌트 주소값을 참조할 수 있다.

  • focus
  • text selection
  • media playback
  • 애니메이션 적용
  • d3.js, greensock 등 DOM 기반 라이브러리 활용
const 주소값을_담는_그릇 = useRef(참조자료형)
// 이제 주소값을_담는_그릇 변수에 어떤 주소값이든 담을 수 있습니다.
return (
    <div>
      <input ref={주소값을_담는_그릇} type="text" />
        {/* React에서 사용 가능한 ref라는 속성에 주소값을_담는_그릇을 값으로 할당하면*/}
        {/* 주소값을_담는_그릇 변수에는 input DOM 엘리먼트의 주소가 담깁니다. */}
        {/* 향후 다른 컴포넌트에서 input DOM 엘리먼트를 활용할 수 있습니다. */}
    </div>);

컴포넌트가 re-render 되더라도 주소값은 바뀌지 않음.

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>);
}
profile
개쩌는 개발자가 되고 싶다 !

0개의 댓글