TIL 49 | Styled Component 초기세팅 - Theme.js & basics

이사감·2021년 5월 24일
1

CSS

목록 보기
12/13
post-thumbnail

영어 문서 읽기 싫어서 한글 자료 찾아다니다가 종택님이 이상한거 보지 말고 공식문서 보라고 해서 내가 기억하려고 쓰는 TIL

토익 공부할 때보다 영어 더 많이 보는 것 같다.
스타일 컴포넌트 scss만큼 쉬울줄 알았는데 넘 어렵다

Basics

스타일 컴포넌트 초기세팅... 맘 급해서 막했다가 시간만 날리고... 그냥 차근차근 공식문서를 봐야겠다 싶었다.

그게 뭔데

리액트에서 컴포넌트 컴포넌트 컴포넌트 정말 많이 듣고 보고 쓰고 다뤘다. 그 컴포넌트에 아예 스타일을 입혀놓은 게 Styled Component. className을 알아서 안 겹치게 지어줌. Sass로 네스팅 해줘도 가끔 충돌 날 때 있어서 이럴거면 네스팅 왜 해~!~! 했었는데 얘는 그럴 일 없다 함. 개꿀👍

기본 문법

  1. render 안에 쓰지 않음. render 바깥에 씀.
  2. 당연한 말이지만 import 해야함~!
    import styled from 'styled-components';

    ...

    render(
      <div>
        <Button>Normal</Button>
        <Button primary>Primary</Button>
      </div>
    );

    const Button = styled.button`
      background: ${props => props.primary ? "palevioletred" : "white"};
      color: ${props => props.primary ? "white" : "palevioletred"};
      font-size: 1em;
      margin: 1em;
      padding: 0.25em 1em;
      border: 2px solid palevioletred;
      border-radius: 3px;
    `;
  1. const Button = styled.button 에서 Button은 스타일링을 줄 컴포넌트 이름을 의미한다. 컴포넌트는 대문자로 시작함을 잊지 말자~ styled.buttonstyled constructor로 어떤 HTML 태그에 스타일을 줄 것인지 선택하는 것인데 button 태그임을 알 수 있다.
    정리하자면 HTML 태그가 button으로 렌더링되는 컴포넌트 Button을 새로 만든 것이당. 뭔말인지 모르겠다면 뚝딱 위의 샘플 코드를 렌더링하여 개발자도구 element 패널에서 해당 컴포넌트가 어떻게 그려져있는지 확인하자. 스타일 컴포넌트는 클래스/함수 컴포넌트랑은 다른 거라는거에 주의 !
    styled.buttonstyled('button')은 똑같다.
    작동 원리는 document.querySelector 등으로 해당 태그명을 선택하는 그런건데 자세한건 이 유튜브 영상에 잘 나와있음.

  2. 지금 이 코드에선 Button 컴포넌트를 렌더링하고 있다. Button 컴포넌트 안에 primary가 보인다. 어디서 많이 본 형태다. props다. 아래의 부분은 props를 활용하여 조건부 스타일링한 것이다.

    background: ${props => props.primary ?
      "palevioletred" : "white"};
  1. styled.button 뒤에 백틱이 보인다. 이 문법을 Tagged Template Literals라고 부른다. ES6 문법인데 스타일 컴포넌트의 핵심인듯? 여기에 설명 잘 되어있당. 템플릿 리터럴의 연장선상이라고 함. 백틱 안에서 모든 CSS 문법을 사용할 수 있다.

스타일 확장

위에서 props를 활용해 조건부 스타일링하는 것을 봤다. 스타일을 확장할 수도 있음.

render(
  <div>
    <Button>Normal Button</Button>
    <TomatoButton>Tomato Button</TomatoButton>
  </div>
);

const Button = styled.button`
  color: palevioletred;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

const TomatoButton = styled(Button)`
  color: tomato;
  border-color: tomato;
`;

TomatoButton 스타일 컴포넌트는 styled constructor로 Button 스타일 컴포넌트를 썼다. 여기다가 Tagged Template Literals로 추가 스타일링을 적었다. 이건 Button 스타일 컴포넌트를 상속받으면서 그 위에 override한다는 것임! 결론적으로 TomatoButton 스타일 컴포넌트엔 다음과 같은 속성이 적용됨.

  color: palevioletred;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
  color: tomato;
  border-color: tomato;

as 키워드로 태그 확장하기(?)

한국어로는 머라고 부를까..?

render(
  <div>
    <Button>Normal Button</Button>
    <Button as="a" href="/">Link with Button styles</Button>
    <TomatoButton as="a" href="/">Link with Tomato Button styles</TomatoButton>
  </div>
);

const Button = styled.button`
  display: inline-block;
  color: palevioletred;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
  display: block;
`;

const TomatoButton = styled(Button)`
  color: tomato;
  border-color: tomato;
`;

원래 Button 스타일 컴포넌트는 button 태그인데, as="a" 를 통해서 button 태그를 a태그로 사용했다. 스타일은 같게, 태그는 다르게 확장.

as로 태그 내용물도(텍스트) 바꿀 수 있다

const DiffButton = props => <Button {...props} children="내용바뀜" />

render(
  <div>
    <Button>Normal Button</Button>
    <Button as={DiffButton}>Custom Button with Normal Button styles</Button>
  </div>
);

이러면 두 번째 버튼은 첫 번째 버튼과 동일한 스타일을 가지지만 내용물 텍스트는 custom 어쩌구가 아니라 내용바뀜으로 들어간다

선택자 : &(앰퍼샌드)와 .

이건 scss랑 똑같음. & 선택자로 자기 자신을 선택하고 .으로 className을 선택한다. scss랑 거의 비슷해서 어렵진 않은데 새로웠던(?)거 🔽

const Thing = styled.div`
  color: blue;

  .something {
    border: 1px solid;
    display: block;
  }
`;

<Thing>
  <label htmlFor="foo-button" className="something">Mystery button</label>
  <button id="foo-button">What do I do?</button>
</Thing>

이러면 Thing 컴포넌트 안의 something className에 스타일을 적용하는 것~

HTML tag attribute까지 선택

const Example = styled.button.attrs(props=>({
  type: 'submit'}))`
  ~~스타일링~~
`;

render(
  <>
    <Example /> // => type이 submit인 button 태그
  </>
);

이런거

const Input = styled.input.attrs(props => ({
  type: "text",
  size: props.size || "1em",
}))`
  border: 2px solid palevioletred;
  margin: ${props => props.size};
  padding: ${props => props.size};
`;

//Input 상속받아 type만 password로 override
const PasswordInput = styled(Input).attrs({
  type: "password",
})``;

render(
  <>
    <Input placeholder="A bigger text input" size="2em" />
    <PasswordInput placeholder="A bigger password input" size="2em" />
  </>
);

이런거

시작하기 (초기세팅)

npm install --save styled-components

GlobalStyles.js

common.scss, reset.scss 대용으로 사용한다. CSS, SCSS를 사용할 때는 reset.css를 구글에서 긁어왔지만 Styled Component는 아예 제공하고 있다.
npm install --save styled-reset 으로 설치하고 GlobalStyles.js에서 import해서 다음과 같이 쓰면 됨.

import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';

const GlobalStyles = createGlobalStyle`
  ${reset};
  ~~따로 설정하고 싶은 Common.scss를 적으면 됨~~
  `;

export default GlobalStyles;

Theme.js

variables.scss 대용으로 사용한다. ThemeProvider를 통해 컴포넌트들에 전달되고, 사용한다. 더 잘 사용하는 방법이 있을 거 같은데 일단 모르겠다...

const calcRem = pxSize => `${pxSize / 16}rem`;

const flexSet = (just = 'center', align = 'center') => {
  return `display: flex;
  justify-content: ${just};
  align-items: ${align};`;
};

const flexColumnSet = (just = 'center', align = 'center') => {
  return `display: flex;
  flex-direction: column;
  justify-content: ${just};
  align-items: ${align};`;
};

const colors = {
  red: '#f26462',
  black: 'rgb(61, 61, 61)',
  primaryGray: '#3f4150',
  secondaryGray: '#8c8d96',
  tertiaryGray: '#b2b3b9',
  border: '#EFEFEF',
  selected: '#f2f2f2',
  bgGray: '#f6f5f5',
};

const theme = {
  colors,
  calcRem,
  flexSet,
  flexColumnSet,
};

export default theme;

colors

css, scss의 variables 파일처럼 자주 쓰는 컬러값들을 저장할 수 있당. 사용할 때는 theme을 props로 받아서 다음과 같이 사용한다.

clacRem

px단위에 익숙하지만 반응형에 대비해 rem 단위로 작업할 건데 매번 px => rem 계산하는 귀찮음을 덜기 위해 calcRem 함수를 작성했다. 아주 좋은거 알았다 ~!

flex Mixin

sass를 사용하면서 flex set을 Mixin으로 아주 잘 썼는데 스타일컴포넌트에서는 어떻게 쓰는지 몰라서 하루종일 삽질함 ༼;´༎ຶ ۝ ༎ຶ༽
일단 저렇게 theme안에 선언하고 아래와 같이 사용하면 아주 잘 적용된다.

사용법

저 theme.js는 다음과 같이 사용할 곳에서 props로 받아 사용하면 된다.

import React from 'react';
import styled from 'styled-components';

function Main() {
  return (
    <>
      <CenterContainer>
        <div>1</div>
        <div>2</div>
        <div>3</div>
      </CenterContainer>
    </>
  );
}

const CenterContainer = styled.div`
  ${({ theme }) => theme.flexSet()}
  font-size: ${({ theme }) => theme.calcRem(50)}
  color: ${({ theme }) => theme.colors.red}
`;

export default Main;

저 둘을 사용하려면 먼저

// index.js에 요 셋을 import 시켜준다
import GlobalStyle from './styles/GlobalStyle';
import { ThemeProvider } from 'styled-components';
import Theme from './styles/Theme';

// 아래와 같이 작성한다
ReactDOM.render(
  <>
    <GlobalStyle />
    <ThemeProvider theme={Theme}>
      <Routes />
    </ThemeProvider>
  </>,
  document.getElementById('root')
);

이러면 Router.js에서 return해주는 컴포넌트들에 전역으로 스타일 속성을 사용할 수 있게 함.

이전에 component들의 depth가 깊어지면서 depth가 너무 깊어져도 계속 props로 넘기고 넘기고 넘기며 사용하나? 하는 생각이 들어서 증조할아버지가 가진 props를 증손주에게 바로 직빵으로 쏴주는 방법 (props drilling)이 없는지 알아볼 때 Context API에 대해 들어본 적 있는데 ThemeProvider의 작동 방식도 그거라고 한다.

간단히만 이야기하자면 전역으로 상태를 사용할 수 있는 영역인 Context를 Provider를 이용해서 지정하는 것이다. Provider로 감싸진 컴포넌트들에서는 Context를 사용할 수 있음. ThemeProvider도 마찬가지이다.

ThemeProvider로 감싸진 자식 Component들은 ThemeProvider로 전달받은 theme를 props로 전달받아서 사용이 가능합니다.

이걸 의존성 주입이라고 한다고 함. Provider로 감싸진 애들이 Context를 주입 받아서 쓴다는 뜻인 것 같다(?). 처음 들었을 때 외계어 같았는데 어려우면 일단 뉘앙스만 이해하면 된다. 뉘앙스 자체는 위에서 계속 이야기했던 것과 똑같다 ! 결국 theme.어쩌고~ 속성들은 각 컴포넌트에 종속된 속성이 아니라 Theme이라는 별도의 공간에 종속된,Theme이라는 공간에 의존하는 것이기 때문에 의존성 주입이라고 이름이 붙여졌다고(?)

Reference

profile
https://emewjin.github.io

0개의 댓글