Styled Component

jinabbb·2022년 4월 12일
0

Styled Component 사용 이유

기존에 scss를 사용해서 스타일링을 했는데,

컴포넌트 파일 1, scss파일 1해서 컴포넌트마다 파일이 2개가 되면서 관리하기가 불편하다.

또, 클래스네임이 중복으로 되면 스타일이 의도대로 나오지 않는다.

이래서 사용하면 좋은게 Styled Component ! 라이브러리이다.

scss를 이용해 만든 스타일들을 styled component로 바꾸면서 알아보자

설치

yarn add styled-components

사용

import styled from 'styled-components'

기본적인 사용방법

기존 Navigation Component

return (
		<Fragment>
			<div className='navigation'>
				<Link to='/' className='logo-container'>
					<CrwnLogo className='logo' />
				</Link>
				<div className='nav-links-container'>
					<Link to='/shop' className='nav-link'>
						SHOP
					</Link>
					{currentUser ? (
						<span className='nav-link' onClick={signOutUser}>
							SIGN-OUT
						</span>
					) : (
						<Link to='auth' className='nav-link'>
							SIGN IN
						</Link>
					)}
					<CartIcon />
				</div>
				{isCartOpen && <CartDropdown />}
			</div>
			<Outlet />
		</Fragment>
	);

기존 Navgation scss

.navigation {
	height: 70px;
	width: 100%;
	display: flex;
	justify-content: space-between;
	margin-bottom: 25px;

	.logo-container {
		height: 100%;
		width: 70px;
		padding: 25px;
	}

	.nav-links-container {
		width: 50%;
		height: 100%;
		display: flex;
		align-items: center;
		justify-content: flex-end;

		.nav-link {
			padding: 10px 15px;
			cursor: pointer;
		}
	}
}

기본 태그 Styled Component로 바꾸기

export const NavigationContainer=styled.div`
	height: 70px;
	width: 100%;
	display: flex;
	justify-content: space-between;
	margin-bottom: 25px;
`

HTML의 기본으로 있는 div,h1등의 태그들은 styled. 으로 만들면되고 뒤에 백틱 안에 스타일 코드를 작성한다.

여기서는 내가 이미 컴포넌트마다 폴더를 만들고 scss와 컴포넌트 파일을 만들어 둬서 기존 scss파일을 자바스크립트 파일로 바꾸고 export하였지만 다음부턴 합쳐서 하나의 파일로 만들면 훨씬 편할것 같다.

커스텀 컴포넌트 Styled Component로 바꾸기

import { Link } from 'react-router-dom';
export const LogoContainer=styled(Link)`
height: 100%;
		width: 70px;
		padding: 25px;
`

styled. 대신 함수를 호출하여 만든다. 기존 Link컴포넌트가 받던 Props들도 LogoContainer가 받게 된다.

최종 navigation.sytles.jsx

import styled from 'styled-components';
import { Link } from 'react-router-dom';

export const NavigationContainer = styled.div`
	height: 70px;
	width: 100%;
	display: flex;
	justify-content: space-between;
	margin-bottom: 25px;
`;
export const LogoContainer = styled(Link)`
	height: 100%;
	width: 70px;
	padding: 25px;
`;

export const NavLinksContainer = styled.div`
	width: 50%;
	height: 100%;
	display: flex;
	align-items: center;
	justify-content: flex-end;
`;

export const NavLink = styled(Link)`
	padding: 10px 15px;
	cursor: pointer;
`;

수정후 navigation.components.jsx

return (
		<Fragment>
			<NavigationContainer>
				<LogoContainer to='/'>
					<CrwnLogo className='logo' />
				</LogoContainer>
				<NavLinksContainer>
					<NavLink to='/shop'>SHOP</NavLink>
					{currentUser ? (
						<NavLink as='span' onClick={signOutUser}>
							SIGN-OUT
						</NavLink>
					) : (
						<NavLink to='auth'>SIGN IN</NavLink>
					)}
					<CartIcon />
				</NavLinksContainer>
				{isCartOpen && <CartDropdown />}
			</NavigationContainer>
			<Outlet />
		</Fragment>
	);

기존에 nav-link 클래스로 같이 스타일링하던 SIGNOUT은 Link컴포넌트가 아닌 span엘리먼트였는데 as태그로 span을 넣어주면서 같은 StyledComponent를 사용할수 있다.

Button 컴포넌트를 StyledComponent로 바꾸기

기존의 Button컴포넌트는 props로 받는 buttonType을 className에 넣어 스타일링한다

기존 Button Component

const BUTTON_TYPE_CLASSES = {
	google: 'google-sign-in',
	inverted: 'inverted',
};

const Button = ({ children, buttonType, ...otherProps }) => {
	return (
		<button
			className={`button-container ${BUTTON_TYPE_CLASSES[buttonType]}`}
			{...otherProps}
		>
			{children}
		</button>
	);
};

Button Styled Component

import styled from 'styled-components';

export const BaseButton = styled.button`
	min-width: 165px;
	width: auto;
	height: 50px;
	line-height: 50px;
	letter-spacing: 0.5px;
	padding: 0 35px;
	font-size: 15px;
	background-color: black;
	color: white;
	text-transform: uppercase;
	font-family: 'Roboto Mono';
	font-weight: bolder;
	cursor: pointer;
	display: flex;
	justify-content: center;
	align-items: center;
	border: none;
	&:hover {
		background-color: white;
		color: black;
		border: 1px solid black;
	}
`;
export const GoogleSignInButton = styled(BaseButton)`
	background-color: #4285f4;
	columns: white;

	&:hover {
		background-color: #357ae8;
		border: none;
	}
`;
export const InvertedButton = styled(BaseButton)`
	background-color: white;
	color: black;
	border: 1px solid black;
	&:hover {
		background-color: black;
		color: white;
		border: none;
	}
`;

기본 버튼인 BaseButton을 만들고 이 컴포넌트를 활용해 다시 구글로그인이나 인버티드 스타일드 컴포넌트를 만든다.

Button Component

import {
	BaseButton,
	InvertedButton,
	GoogleSignInButton,
} from './button.styles.jsx';

export const BUTTON_TYPE_CLASSES = {
	base: 'base',
	google: 'google-sign-in',
	inverted: 'inverted',
};

const getButton = (buttonType = BUTTON_TYPE_CLASSES.base) =>
	({
		[BUTTON_TYPE_CLASSES.base]: BaseButton,
		[BUTTON_TYPE_CLASSES.google]: GoogleSignInButton,
		[BUTTON_TYPE_CLASSES.inverted]: InvertedButton,
	}[buttonType]);

const Button = ({ children, buttonType, ...otherProps }) => {
	const CustomButton=getButton(buttonType);
	return (
		<CustomButton
			{...otherProps}
		>
			{children}
		</CustomButton>
	);
};

button_type을 상수로 만들고 각 버튼의 용도에 맞는 스타일드 컴포넌트를 리턴하는 함수를 만들어서 사용한다.

이렇게 만들면 다른데서 Button 컴포넌트를 사용할때 button_type_class까지 import해서 사용하면 어떤 타입이 있는지도 알 수 있고 , 자동완성을 통해 오타실수도 예방할 수 있다.

Styled component안에서 다른 StyledComponent 스타일링

import { BaseButton } from '../button/button.styles';
export const CartDropdownContainer = styled.div`
	${BaseButton} {
		margin-top: auto;
	}
`;

StyledComponent의 장점이 classname을 개발자가 직접 주지 않고 스타일링을 하여 에러를 예방하는데, 하위 StyledComponent를 스타일링하려고 classname을 주는건 옳지 않다.

이걸 방지하기 위해 StyledComponent에서 위와 같이 다른 StyledComponent를 import하여 스타일링 할 수 있다.

Styled Component에서 Props사용하기

export const BackgroundImage = styled.div`
	width: 100%;
	height: 100%;
	background-size: cover;
	background-position: center;
	background-image: ${({ imageUrl }) => `url(${imageUrl})`};
`;

<BackgroundImage
				imageUrl={imageUrl}
			></BackgroundImage>

위와 같이 Props로 전달되는 변수들을 Sytled Component에서 사용할 수 있다.

scss의 mixin , 변수등도 비슷하게 가능하다

기존 form-input style scss

$sub-color: grey;
$main-color: black;

@mixin shrinkLabel {
	top: -14px;
	font-size: 12px;
	color: $main-color;
}

.group {
	position: relative;
	margin: 45px 0;

	.form-input {
		background: none;
		background-color: white;
		color: $sub-color;
		font-size: 18px;
		padding: 10px 10px 10px 5px;
		display: block;
		width: 100%;
		border: none;
		border-radius: 0;
		border-bottom: 1px solid $sub-color;
		margin: 25px 0;

		&:focus {
			outline: none;
		}
		&:focus ~ .form-input-label {
			@include shrinkLabel();
		}
	}

	input[type='password'] {
		letter-spacing: 0.3em;
	}

	.form-input-label {
		color: $sub-color;
		font-size: 16px;
		font-weight: normal;
		position: absolute;
		left: 5px;
		top: 10px;
		transition: 0.3s ease all;

		&.shrink {
			@include shrinkLabel();
		}
	}
}

기존 form-input component

import './form-input.styles.scss';
const FormInput = ({ label, ...otherProps }) => {
	return (
        <div className='group'>
            <input className='form-input' {...otherProps} />
			{label && (
                <label
                className={`${
                    otherProps.value.length ? 'shrink' : ''
                } form-input-label`}
				>
					{label}
				</label>
			)}
		</div>
	);
};
export default FormInput;

form input styled component로 변경

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

const subColor = 'grey';
const mainColor = 'black';

const shrinkLabelStyles = css`
	top: -14px;
	font-size: 12px;
	color: ${mainColor};
`;

export const FormInputLabel = styled.label`
	color: $sub-color;
	font-size: 16px;
	font-weight: normal;
	position: absolute;
	left: 5px;
	top: 10px;
	transition: 0.3s ease all;

	${({ shrink }) => shrink && shrinkLabelStyles}
`;

export const Input = styled.input`
	background: none;
	background-color: white;
	color: ${subColor};
	font-size: 18px;
	padding: 10px 10px 10px 5px;
	display: block;
	width: 100%;
	border: none;
	border-radius: 0;
	border-bottom: 1px solid ${subColor};
	margin: 25px 0;

	&:focus {
		outline: none;
	}
	&:focus ~ ${FormInputLabel} {
		${shrinkLabelStyles}
	}
`;

export const Group = styled.div`
	position: relative;
	margin: 45px 0;
	input[type='password'] {
		letter-spacing: 0.3em;
	}
`;

styled-components라이브러리의 css함수로 스타일을 만들어서 사용한다.

profile
개발

0개의 댓글