Styled-components 가이드

부수 기본 개념

 

Template Literal

 

문자열 안에 특정 자바스크립트 값을 넣어서 조합을 할때 쉽게 해줄수 있는 방법 (backtick사용)

 

const name = 'react';
const message = `hello ${name}`;

console.log(message);

// "hello react"

문자열이 아닌 object를 사용하였을시에는 다르다.

 

const object = {a : 1};
const text = `${object}`;

console.log(text);

// "[object Object]"

함수경우에도 함수 문자열형태그 그대로 들어가진다.

const fn = () => true
const msg = `${fn}`;

console.log(msg);

// "() => true"

favoriteColors () 대신 `` 를 사용하면?

const red = '빨간색';
const blue = '파란색';

function favoriteColors(texts, ...values) {
	console.log(texts);
	console.log(values);
}

favoriteColors `제가 좋아하는 색은 ${red}과 ${blue}입니다.`

favoriteColors () 대신 `` 를 사용하면? 2

const red = '빨간색';
const blue = '파란색';

function favoriteColors(texts, ...values) {
	return texts.reduce((result, text, i) =>  
           `${result}${text}${values[i] ? `<b>${values[i]}</b>` : ''}' , '');
}

favoriteColors `제가 좋아하는 색은 ${red}과 ${blue}입니다.`

//제가 좋아하는 색은 <b>빨간색</b>과 <b>파란색</b> 입니다.

이런 ``backtick으로 styled component를 사용한다

const Circle = styled.div`
    width : 5px;
    height : 5px;
    background : balck;
    border-radius: 50%;
`;

function App() {
    return <Circle />;
}

export default App;

Text

결과 ->

styled-components 문법을 backtick으로 감싸고 있는 상태에서

부모를 template Literal방식으로 가져온다

const Circle = styled.div`
    width : 5px;
    height : 5px;
    background : ${props => props.color};
    border-radius: 50%;
`;

function App() {
    return <Circle color="blue" />;
}

export default App;

결과 ->

huge값이 ture라면 다음과같이...

const Circle = styled.div`
    width : 5px;
    height : 5px;
    background : ${props => props.color};
    border-radius: 50%;
    ${props => 
        props.huge &&
        `
        width : 10px;
        height : 10px;
        `}
`;

function App() {
    return <Circle color="blue" huge />;
}

export default App;

하지만 template Literal 안에 또다른 부모를 호출할순 없다...그렇다면?

styled-components에서 제공하는 css를 사용해보자

import styled, { css } from 'styled-components';

const Circle = styled.div`
    width : 5px;
    height : 5px;
    background : ${props => props.color};
    border-radius: 50%;
    ${props => 
        props.huge &&
        css`
        ${props .....}
        width : 10px;
        height : 10px;
        `}
`;

function App() {
    return <Circle color="blue" huge />;
}

export default App;

Styled-components 이름지정

객체의 이름을 생성할시( 스타일 컴포넌트)

앞글자는 꼭 대문자여야합니다.



const Buttons = styled(Button)`
         width :  ${props => props.theme.buttonWidth};
         margin :  ${props => props.theme.buttonMargin};
        `;
     
    //success
   const PlusButton = styled(Buttons)``;
    
    //error
    const minusButton = styled(Buttons)``;

minusButton 과같이 컴포넌트를 생성한다면 오류발생입니다.

(스타일컴포넌트가 아닌 원래 컴포넌트 생성시 주의사항)

속성값 입력시에는 '' or "" 를 감싸지 않는다



const Buttons = styled(Button)`
         width :  10px;
         margin :  5px 10px 10px 50px;
         background-color : red;
        `;
     
    //success
   const PlusButton = styled(Buttons)``;
    
    //error
    const minusButton = styled(Buttons)``;

스타일 컴포넌트 생성시

ex)


const DeleteButton = styled.div`
         background-color : "red"; 
      `;

현재 프로젝트에서는 Ant Design을 통한 UI Framework를 사용중입니다.

1.기본 UI 요소를 정할시 다음과 같은 방법으로

 스타일 변수를 다음과 같은 방법으로 생성 합니다.

html 요소(위에 예제에서는 div)를 styled하는 styled-components 라이브러리를 이용하여 다음과같이 생성합니다.

*생성 이름은 꼭 맨앞이 대문자여야만 합니다.

ex)

import {Button, Modal, Select, Table} from "antd";

...

const DeleteButton = styled(Button)`
         background-color : "red"; 
      `;

2. UI(ant design과 같은경우)FrameWork 수정시에는 

다음과 같이 설정합니다.

antDesign의 Button UI를 styled-components를 적용해 다음과 같이

설정하여줍니다.

ex)

import {Button, Modal, Select, Table} from "antd";

...


        const Buttons = styled(Button)`
              margin-left : 10px;
        `;

        const ExcelDownButton = styled(Buttons)`
              margin-left : 30px;      
        `;

3. 비슷하거나 겹치는 스타일 설정에대한 컴포넌트를 

생성할시에 다음과 같이 정의합니다.

생성한 스타일 컴포넌트 변수를 

매개변수로서 다시 styled에 주입하여 생성합니다.

이때 추가로 입력할 스타일 요소가 있다면 추가가 가능합니다.

ex)

import {Button, Modal, Select, Table} from "antd";

...
	
export const borderProps = props => css`
  ${props.borderBottom && `border-bottom: ${props.borderWidth || "1px"} solid ${color.border}`};
  ${props.borderTop && `border-top: ${props.borderWidth || "1px"} solid ${color.border}`};
  ${props.borderLeft && `border-left: ${props.borderWidth || "1px"} solid ${color.border}`};
  ${props.borderRight && `border-right: ${props.borderWidth || "1px"} solid ${color.border}`};
`;

4.별도의 파일로 분류하여 사용을 할 상황이면

다음과 같이 진행한다.

css ` ... ` 는 styled-components가 제공하는 기능으로 ...에대한 요소들을 css기능으로 묶어 props로 전달하는 기능이다. 

 

스타일 컴포넌트 안에 집어넣을때는 Template Literal방식으로 넣는다.

ex) ${borderProps}

import styled from "styled-components";
import {Layout} from "antd";
const {Header} = Layout;

export const IndexLayout = styled.div`
      display:grid;
      grid-template-columns: 100% auto;
      grid-template-rows: 60px auto;
      width : 100%;
      height : 100%
    `;

export const DexiLogo = styled.img`
      width : 32px;
      height : 32px;
      line-Height : 60px;
      margin : 4px 15px 4px 0px;
   `;

export const TopHeader = styled(Header)`
    grid-column-start:1;
    grid-column-end:4; 
    flex-direction:row; 
    flex: 0 0 auto;
    `;

export const TopRightMenu = styled.div`
    margin-top : 7px;
     float : right;
    `;
export default IndexLayout;

5.스타일 컴포넌츠 파일분리

스타일드 컴포넌트들을 export시켜 

다음과같이 불러와 사용하였다.

import {DexiLogo, TopHeader, TopRightMenu} from '../../IndexLayout';

....

<TopHeader>
<DexiLogo>
......
</DexiLogo>

<TopRightMenu>
......
</TopRightMenu>

</TopHeader>

export 시킨 컴포넌트를 import 하여 사용하였다.

themeProvider 같은 전역으로 공통된 부분이 아닌 일부분에 필요한 스타일 컴포넌츠를 사용할때 파일을 분리해야한다면 이런 방법을 사용한다.

글로벌 변수 ( themeProvider 사용할시)

상위 컴포넌츠에 다음 예제와 같이 사용합니다.

ex)

const theme = {
    buttonWidth : "50px",
    buttonMargin : "5px"
    // 이런식으로 전체 컴포넌트에 넣어줄 것들 생성
};

<ThemeProvider theme={theme}>
                    <IndexPage/>
                </ThemeProvider>

많은컴포넌트에 공통으로 사용하는 스타일에 주로 사용합니다.

const theme 파일을 별도의 파일로 분류하는 것은 자유입니다.

store 저장소 mobx 사용시에

수시로 변하는 value를 적용하여 theme를 변화줄수 있습니다.

@inject('commonStore')
@observer
class App extends Component<any, any> {

    render() {

        const {commonStore} = this.props;

        const theme ={
            main : commonStore.getColor
        };

        return (
            <Layout>
                <ThemeProvider theme={theme}>
                    <IndexPage/>
                </ThemeProvider>
            </Layout>
        );
    }

commonStore.getColor(mobx)로 변한 value류가 다시 ThemeProvider를 타고 

값을 전역에 전달합니다.

themeprovider를 다음과같이 로드하여 사용합니다.

ex)

const Buttons = styled(Button)`
         width :  ${props => props.theme.buttonWidth};
         margin :  ${props => props.theme.buttonMargin};
        `;

여러 컴포넌트에서 일괄적으로 변경해야 할시 

const theme의 요소에서 한번만 수정해주면 여러 반복요소를 줄일수 있습니다.

ex)

//예로 Button 컴포넌트를 만들고 부모값으로 보낼 size를 설정
<Button size="small">Button</Button>
<Button size="large">Button</Button>
<Button size="default">Button</Button>

부모로 받는 값에따라 변해야하는경우 (조건에 따른 설정)

ex)

  const sizeStyles = css`
            ${props => props.size === 'large' && 
            css`
                height : 10px;
                font-size: 8px;
            `}
            ${props => props.size === 'default' &&
            css`
                 height : 8px;
                 font-size: 5px;
             `}
             ${props => props.size === 'small' &&
            css`
                 height : 5px;
                 font-size: 3px;
             `}          
`;

const StyledButton = styled.button`
    /*...공통스타일*/
       /*템플레이트 리터럴*/
    ${sizeStyles}
`;

통상방법

ex)

  const sizes = {
    large: {
        height : '10px',
        fontSize: '8px'
},
    default: {
        height : '7px',
        fontSize : '5px'
},
    small: {
        height : '5px',
        fontSize : '3px'
}

};

const sizeStyles = css`
    ${({ size }) => css`
        height : ${sizes[size].height};
        font-size : ${sizes[size].fontSize};
    `}
`;

const StyledButton = styled.button`
    /*...공통스타일*/
       /*템플레이트 리터럴*/
    ${sizeStyles}
`;

적용방법

예제 같은 경우도 Store저장소의 값의 변화에따라 달라질수 있으므로 

size value에 mobx 값을 받도록 하였다.

ex)

//예로 Button 컴포넌트를 만들고 부모값으로 보낼 size를 설정
<Button size="small">Button</Button>
<Button size="large">Button</Button>
<Button size="default">Button</Button>
ex)

//예로 Button 컴포넌트를 만들고 부모값으로 보낼 size를 설정
<Button size={commonStore.getFontSize}>Button</Button>
<Button size="large">Button</Button>
<Button size="default">Button</Button>


const Buttons = styled(Button)`
         width :  ${props => props.theme.buttonWidth};
         margin :  ${props => props.theme.buttonMargin};
        `;
     
    //success
   const PlusButton = styled(Buttons)``;
    
    //error
    const minusButton = styled(Buttons)``;

위와같이 컴포넌트를 상속하는것 보다는 



const Buttons = css`
         width :  ${props => props.theme.buttonWidth};
         margin :  ${props => props.theme.buttonMargin};
        `;

   const PlusButton = styled.button`
        ${Buttons}
    `;
   
    const MinusButton = styled.button`
        ${Buttons}
    `;

css를 분리 적용하는쪽을 주로 사용하였다.



const Buttons = styled(Button)`
         width :  ${props => props.theme.buttonWidth};
         margin :  ${props => props.theme.buttonMargin};
        `;
     
    //success
   const PlusButton = styled(Buttons)``;
    
    //error
    const minusButton = styled(Buttons)``;

타입스크립트 적용시.

스크립트상에서 사용하는 언어이기때문에

타입지정이 필요할 수 있습니다.

ex)
import styledComponents from 'styled-components'
import styledComponentsTS from 'styled-components-ts'


export interface MyImageProps {
  size: number
  borderColor?: string
  borderSize?: number
}


const MyImage = styledComponentsTS<MyImageProps>(styledComponents.img) `
  width: ${props => props.size}px;
  height: ${props => props.size}px;
  border: ${props => props.borderSize || '4px'} solid ${props => props.borderColor || 'black'}
`


<MyImage size={300} borderColor="blue" borderSize={10} />

 

MyImage 에 대한 속성타입지정은 사실상 ts파일에 따로 분류하여 설정합니다.

deck

By Beom lee