styled-components- ThemeProvider 적용하기

heyj·2022년 3월 22일
8

wanted_PreOnboarding

목록 보기
5/7

현재 진행하고 있는 프로젝트의 기능구현은 마무리했는데, 반응형이 아쉬워서 약간 수정을 하기로 했습니다.

애초 모바일 사이즈까지 고려한 반응형을 만들 생각이었다면 디자인을 이렇게 하지 않았을텐데 후회를 했습니다.ㅜㅜ
지금 디자인으론 모바일 사이즈를 만들어봐야 예쁘지 않을 것 같아서 당장은 600, 768, 1024 단위로 적용했습니다.

styled-components의 Global style 적용은 해봤지만 ThemeProvider를 이용해본적은 없어서 이번 기회에 사용해 봤습니다.

1. styled-components ThemeProvider

styled-components의 ThemeProvider는 context api 기반으로 만들어진 것으로, Context api의 방식대로 Provier로 감싼 Component들은 theme정보를 props형태로 넘겨받아서 사용 할 수 있습니다.

우선 styles/theme.js 파일을 생성해 전역에서 쓰일 변수들과 값을 세팅해줬습니다.


const windowSize = {
  small: 'screen and (max-width: '600px')',
  base: 'screen and (max-width: '768px')',
  large: 'screen and (max-width: '1024px')',
};

const fontSize = {
  xs: '0.5rem',
  sm: '0.75rem',
  base: '1rem',
  md: '1.25rem',
  lg: '1.5rem',
};

const lightversion = {
  background: '#fff',
  fontPrimary: 'black',
  fontSecondary: 'gray',
  primary: '#00a0ff',
  secondary: '#ddd',
  hover: '#00a0ff50',
};

const repo = {
  open: 'red',
  close: 'blue',
};

const theme = {
  windowSize,
  repo,
  fontSize,
  lightversion,
};

export default theme;

lightversion은 추후 다크모드(두근두근!!)를 적용하기 위해 만들어뒀습니다. 다크모드 UI는 이번에 꼭 만들어서 적용해 볼겁니다..ㅠㅠ

2. Provider 적용하기

App component에 provider를 적용했습니다.
styled-components에서 ThemeProvider를, 그리고 만들어둔 theme.js 파일을 import해 와서 적용하고자 하는 컴포넌트를 감싸 작성하면 됩니다.

import theme from './stlyes/theme';
import { ThemeProvider } from 'styled-components';

function App() {
  const [repository, setRepository] = useState([]);
  const [userInfo, setUserInfo] = useState([]);

  return (
    <AppComponent>
      <ThemeProvider theme={theme}>
        <Routes>
          ...
        </Routes>
      </ThemeProvider>
    </AppComponent>
  );
}

3. 반응형 적용하기

CSS-in-JS가 번들이 커져 초기 로딩이 느려지고, 인터렉션이 CSS-in-CSS보다 늦다는 단점은 있으나, props전달방식으로 CSS를 구현할 수 있다는 건 정말 장점인 것 같습니다.

아래 예제는 검색버튼(input, submit)에 반응형을 추가해 준 것입니다.
사실 그냥 숫자와 색상코드를 바로 적어두면 코드도 깔끔하고 가독성도 올라갈 것 같습니다만, 유지보수를 고려한다면 당연히 공통으로 쓰이는 것들은 묶어두는 게 낫다는 생각을 했습니다.

반응형의 경우 현재 0.75rem으로 값이 할당되어져 있는 sm을 일괄 1rem으로 변경하고 싶다면, theme.js의 sm값만 변경해주면 되기 때문입니다.

여러모로 styled-components의 장점에 빠져들고 있습니다...@.@

const SearchButton = styled.input`
  width: 20%;
  margin-left: 5px;
  border: none;
  border-radius: 3px;
  font-size: ${({ theme }) => theme.fontSize.md};
  color: ${({ theme }) => theme.lightversion.fontSecondary};
  cursor: pointer;
  transition: transform 200ms ease-in;
  &:hover {
    transform: scale(1.05);
    background-color: ${({ theme }) => theme.lightversion.hover};
    color: ${({ theme }) => theme.lightversion.fontPrimary};
  }
  @media ${({ theme }) => theme.device.base} {
    margin-left: 10px;
    font-size: ${({ theme }) => theme.fontSize.base};
  }
  @media ${({ theme }) => theme.device.small} {
    font-size: ${({ theme }) => theme.fontSize.sm};
    margin-left: 10px;
  }
`;

만약 특정 값이 변경될 때 CSS 값을 변경해줘야 하는 상황이라면 ${({theme)} => theme.....} 방식이 아닌 useContext를 이용하면 속성값을 넘겨줄 수도 있습니다.

// theme.js
const repo = {
  open: 'red',
  close: 'blue',
};

// 해당 컴포넌트
import React, {useContext} from 'react';
import styled, {ThemeContext} from 'styled-components';

const ItemCard = (props) => {
  const theme = useContext(ThemeContext)
  ...
  
  return (
    <State state={issue.closed_at === null ? ${theme.repo.open} : ${theme.repo.close}>
      {issue.closed_at === null ? 'Open' : 'Close'}
    </State>
  )
}

const State = styled.span`
  color: ${(props) => (props.state)};
`;

4. 완성

0개의 댓글