Useful tip Styled-components

namezin·2020년 12월 5일
10

Front-End

목록 보기
19/21
post-thumbnail

참고
10 useful tips for Styled Components

1. 자동 prefixing

언급하지 않아도 되는 기능이지만 css, sass 스타터들을 위해(나를 포함) 설명합니다. 매우매우 좋은 기능입니다.

자동 prefixing(auto-prefixing)이 무엇인가요?

당신의 css에 여러 브라우저에 동작할 수 있도록 자동으로 prefix를 해주는 것입니다.

display: flex;
flex-direction: row;

위 처럼 작성하더라도 아래와 같이 자동 prefixing 해줍니다.

-ms-flex: 1;
flex: 1 1;
display: -ms-flexbox;
display: flex;
-ms-flex-direction: row;
flex-direction: row;

2. attrs

'attrs'를 잊지 마세요.
그리고 'attrs'는 props에 접근하여 사용할 수 있습니다.

const InputText = styled.input.attrs({
  type: 'text',
  placeholder: props => props.placeholder || 'Please fill',
})`
  padding: 6px 12px; 
`;

3. 다양한 css framework와 같이 사용될 수 있습니다.

'attrs'를 사용하여 className attribute를 사용할 수 있습니다.
그래서 css framework를 styled-components로 쉽게 변환할 수 있습니다.

const Button = styled.button.attrs({
  className: 'btn btn-primary'
})``;
// With some dynamic props
const Button = styled.button.attrs({
  className: `btn btn-primary btn-${props => props.size || 'medium'}`
})``;

<Button size="small" />
.btn{
  background: whiteSmoke;
  color: black;
  width: 10rem;
  font-size: 1rem;
  ...
  &-primary{
    background: red;
    color: white;
    ...
  }
  &-small{
    width: 5rem;
    font-size: 0.75rem;
    ...
  }
  &-medium{
    width: 7.5rem;
    font-size: 0.85rem;
    ...
  }
}

4. withComponent

withComponent를 통해서 component를 쉽게 바꿀 수 있습니다.
가령 buttona component로 간단하게 변경할 수 있습니다.

const PrimaryButton = styled.button`
  background-color: blue;
`;

const PrimaryLink = PrimaryButton.withComponent('a');

5. Nested rules, media query 사용가능

nested rules: 중괄호를 통한 하위 스타일 쉽게 접근 가능한 스타일 구문
media query: 반응형 스타일을 위한 스타일 구문

const MyBox = styled.div`
  width: 500px;
  height: 300px;
  ::before {
    content: '';
  }
  ::after {
    content: '';
  }
  li::first-child {
    content: '';
  }
  @media (max-width: 700px) {
    background: palevioletred;
  }
`;

6. Reverse Selector Pattern

css에서 하지 못했던 element의 부모요소에 접근가능합니다.
(매우 흥미로운 부분입니다.)

const Link = styled.a`
  display: flex;
  align-items: center;
  padding: 5px 10px;
  background: papayawhip;
  color: palevioletred;

  &:hover svg { ... } // {1}
`;

const Icon = styled.svg`
  transition: fill 0.25s;
  width: 48px;
  height: 48px;

  ${Link}:hover & { // {2}
    fill: rebeccapurple;
  }
`;

{1} : <-- css에서는 이렇게 작성해야만 Link hover 시 자식요소인 svg에 접근가능합니다.
{2} : <-- styled-component에서는 Link를 하위요소인 svg에서 접근하여 hover와 같은 스타일을 줄 수 있습니다.

7. Theme context api가 내장되어 있습니다.

import styled, { ThemeProvider } from 'styled-components';
const theme = {
  primaryColor: 'salmon',
  fontFamily: 'Bebas',
};

const Button = styled.button`
  background: ${props => props.theme.primaryColor}
  font-family: ${props => props.theme.fontFamily}
`;

<ThemeProvider theme={theme}>  
  <Button />
  
  {/* Or you can override */}
  <Button theme={{ primaryColor: 'green' }} />
</ThemeProvider>

theme을 통해서 style관리를 편하게 할 수 있습니다.

typescript 쓸 시에는 theme타입은 DefaultTheme으로 정의됩니다.

styled-components DefaultTheme 에 타입을 정의해두고 export하면 접근하여 사용할 수 있습니다.

declare module "styled-components" {
  export interface DefaultTheme {
    primaryColor: string;
    secondaryColor: string;
    ...
  }
}
import { DefaultTheme } from "styled-components";

export const theme: DefaultTheme = {
  primaryColor:  "#111111";
  secondaryColor: "#333333";
  ...
}

8. Compositions & Mixins pattern

styled-components의 css helper와 polished package를 이용하면 쉽게 구현가능합니다.

polished 는 styled-components에서 제공하고 있습니다.

가령 sass에서 사용되는 darken,lighten 이 있습니다.

import { css } from 'styled-components';

const boxShadowMixin = css`
  box-shadow: 0 0 0 rgba(0, 0, 0, 0.5);
`;

const boxShadowMixinFunc = (top, left, blur, color, inset = false) => {
 return `box-shadow: ${inset ? 'inset' : ''} ${top}px ${left}px ${blur}px ${color};`;
}

const StyledComp = styled.div`
  ${boxShadowMixin}
  ${boxShadowMixinFunc(0, 0, 4, 'rgba(0, 0, 0, 0.5)')}
`;

9. style overriding

  1. 반복된 &&만큼 자기자신의 className을 생성합니다. 더 많이 사용할 수록 style 우선순위는 높아집니다.
// Override Existing style
const MyStyledBox = styled(AlreadyStyledComponent)`
  &&& {
    color: palevioletred;
    font-weight: bold;
  }
`;
// Became
.MyBox.MyBox.MyBox {
  color: palevioletred;
  font-weight: bold;
}
  1. 인라인 스타일도 overriding 가능합니다.
// Override Inline style
const MyStyledComponent = styled(InlineStyledComponent)`
  &[style] {
    font-size: 12px !important;
    color: blue !important;
  }
`;

10. Short if

간단한 조건문을 넣을 때 좋은 snippet입니다.

background-color: ${props =>
  (props.type === 'primary' && 'blue') || 
  (props.type === 'danger' && 'red') ||
  (props.type === 'warning' && 'yellow') ||
}

# react typescript props

react typescript에서 styled-components로 props 사용하려면 type을 정의해주어야 합니다.

const Button = styled.button<{isPrimary: boolean}>`
  background: ${props => props.isPrimary ? 'red' : 'white'};
`;


<Button isPrimary={true} />

그런데 위와 같은 camelCase 변수명으로 작성을 하게 되면 아래와 같은 warning이 나타난다.

React does not recognize the isPrimary prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase isPrimary instead. If you accidentally passed it from a parent component, remove it from the DOM element.

props는 React Node를 거쳐서 오기 때문에 DOM 요소로 인식되거나 렌더링되는 것을 막아야 합니다.

styled-component docs에서는 위와 같은 것을 막기 위해서 몇가지 제공되는 것이 있습니다.

transient props

$와 함께 변수명을 생성하여 사용합니다.

const Button = styled.button<{$isPrimary: boolean}>`
  background: ${props => props.$isPrimary ? 'red' : 'white'};
`;


<Button $isPrimary={true} />

shouldForwardProp

transient props 보다 더 동적이고 세분화된 방법입니다.

많은 hoc components들이 함께 compose되는 상황이고 같은 prop name을 공유해야되는 경우에 사용하기 좋습니다.

withConfigshouldForwardProp를 통해 사용합니다.

shouldForwardProp 기능은 Array.filter와 유사합니다.

const Comp = styled('div').withConfig({
  shouldForwardProp: (prop, defaultValidatorFn) =>
      !['hidden'].includes(prop)
      && defaultValidatorFn(prop),
}).attrs({ className: 'foo' })`
  color: red;
  &.foo {
    text-decoration: underline;
  }
`;

render(
  <Comp hidden draggable="true">
    Drag Me!
  </Comp>
);
profile
개발관심자

1개의 댓글

comment-user-thumbnail
2020년 12월 15일

Hello, I enjoy reading all of your article. I like to write a little comment to support you.JOKER123

답글 달기