[패스트캠퍼스 수강 후기] 프론트엔드 인강 100% 환급 챌린지 34회차 미션 - 31강 Sass props 설정 적용하기
props 만들고 설정해주기
버튼에 color props 추가하기
기존에 우리가 만든 버튼은 파랑이었는데 이번에는 핑크, 그레이도 한번 추가해보도록 하자. 색상 선택이 고민될때는 open-color라는 사이트를 이용하면 밝기별로 색상표가 나와있어서 사용하기에 좋다.
자, 그럼 Button 컴포넌트에 아래와 같이 color props를 추가해보자.
Button.js
import React from "react";
import classNames from "classnames";
import "./Button.scss";
// size: large, medium, small
// color : blue, pink, gray
function Button({ children, size, color }) {
return (
<button className={classNames("Button", size, color)}>{children}</button>
);
}
Button.defaultProps = {
//가장정석적인 defualt설정
size: "medium",
color: "blue",
};
export default Button;
그리고 아래와 같이 color별 변수를 만들어주고 버튼의 컬러마다 각각의 스타일을 만들어주면 된다.
Button.scss
$blue: #228be6; //변수 생성
$gray: #495057;
$pink: #f06595;
.Button {
display: inline-flex;
align-items: center;
justify-content: center;
color: #fff;
font-weight: bold;
outline: none;
border: none;
border-radius: 4px;
cursor: pointer;
padding-left: 1rem;
padding-right: 1rem;
transition: 0.2s all;
&.large {
height: 3rem;
font-size: 1.25rem;
}
&.medium {
height: 2.25rem;
font-size: 1rem;
}
&.small {
height: 1.75rem;
font-size: 0.875rem;
}
//버튼 컬러별 스타일링
&.blue {
background: $blue;
&:hover {
background: lighten($blue, 10%);
box-shadow: 2px 2px 2px rgba($color: #000000, $alpha: 0.2);
transition: 0.2s all;
}
&:active {
background: darken($blue, 10%);
box-shadow: inset 2px 2px 5px rgba($color: #000000, $alpha: 0.1);
}
}
&.pink {
background: $pink;
&:hover {
background: lighten($pink, 10%);
box-shadow: 2px 2px 2px rgba($color: #000000, $alpha: 0.2);
transition: 0.2s all;
}
&:active {
background: darken($pink, 10%);
box-shadow: inset 2px 2px 5px rgba($color: #000000, $alpha: 0.1);
}
}
&.gray {
background: $gray;
&:hover {
background: lighten($gray, 10%);
box-shadow: 2px 2px 2px rgba($color: #000000, $alpha: 0.2);
transition: 0.2s all;
}
&:active {
background: darken($gray, 10%);
box-shadow: inset 2px 2px 5px rgba($color: #000000, $alpha: 0.1);
}
}
& + & {
margin-left: 1rem;
}
}
그런데 위의 scss코드를 보면 색상별로 중복되는 코드가 좀 거슬린다. blue, pink, gray가 모두 비슷한 코드에 변수명만 다른것을 볼 수 있다. 이럴때는 scss의 mixin을 사용해주면 되는데 방법은 아래와 같다.
//자주 반복되는 구간을 복사한다. 그리고 믹스인을 새로 생성한다.
@mixin button-color($color) {
//@mixin 이름( 파라미터 - 컬러이름을 받아올 곳)
background: $color;
&:hover {
background: lighten($color, 10%);
box-shadow: 2px 2px 2px rgba($color: #000000, $alpha: 0.2);
transition: 0.2s all;
}
&:active {
background: darken($color, 10%);
box-shadow: inset 2px 2px 5px rgba($color: #000000, $alpha: 0.1);
}
}
이렇게 중복되는 코드를 파라미터로 받아올 수 있게 만들어주고 원래 코드가 있던 부분에는 아래와 같이 include해준다.
&.blue {
@include button-color(
$blue
); //button-color라는 믹스인에 컬러변수를 파라미터로 보내줌.
}
&.pink {
@include button-color($pink);
}
&.gray {
@include button-color($gray);
}
이제 App.js로 돌아가서 우리가 만든 버튼 컴포넌트를 불러서 확인해보자.
App.js
import React from "react";
import Button from "./components/Button";
import "./App.scss";
function App() {
return (
<div className="App">
<div className="buttons">
<Button size="large">Button</Button>
<Button>Button</Button>
<Button size="small">Button</Button>
</div>
<div className="buttons">
<Button size="large" color="gray">
Button
</Button>
<Button color="gray">Button</Button>
<Button size="small" color="gray">
Button
</Button>
</div>
<div className="buttons">
<Button size="large" color="pink">
Button
</Button>
<Button color="pink">Button</Button>
<Button size="small" color="pink">
Button
</Button>
</div>
</div>
);
}
export default App;
위와 같이 잘 나오는 것을 볼 수 있다.
자 이제 나머지 props들도 함께 완성해보자.
outline, fullWidth props 추가하기
이번엔 버튼에 선만 있는 스타일인 outline과 버튼이 100% 꽉 차는 fullWidth의 prpos를 만들어 볼 것이다. 먼저 Button 컴포넌트에 두가지 props를 추가하자.
Button.js 안의 fuction Button 수정
function Button({ children, size, color, outline, fullWidth }) {
return (
<button
className={classNames("Button", size, color, {
//이 둘은 true or false만 있기때문에 객체형태로 받아와준다고함.
outline,
fullWidth,
})}
>
{children}
</button>
);
}
그리고 scss에서 outline같은 경우는 컬러별로 만들어야 하니까 mixin안에 만들어주고 fullWidth는 전체적으로 적용하는 것이니 &.fullWidth로 만들어보자. 코드는 아래와 같다.
Button.scss
$blue: #228be6;
$gray: #495057;
$pink: #f06595;
@mixin button-color($color) {
//@mixin 이름(파라미터)
background: $color;
&:hover {
background: lighten($color, 10%);
box-shadow: 2px 2px 2px rgba($color: #000000, $alpha: 0.2);
transition: 0.2s all;
}
&:active {
background: darken($color, 10%);
box-shadow: inset 2px 2px 5px rgba($color: #000000, $alpha: 0.1);
}
//outline 추가
&.outline {
color: $color;
background: none;
border: 1px solid $color;
&:hover {
background: $color;
color: #fff;
}
}
}
.Button {
display: inline-flex;
align-items: center;
justify-content: center;
color: #fff;
font-weight: bold;
outline: none;
border: none;
border-radius: 4px;
cursor: pointer;
padding-left: 1rem;
padding-right: 1rem;
transition: 0.2s all;
&.large {
height: 3rem;
font-size: 1.25rem;
}
&.medium {
height: 2.25rem;
font-size: 1rem;
}
&.small {
height: 1.75rem;
font-size: 0.875rem;
}
&.blue {
@include button-color($blue);
}
&.pink {
@include button-color($pink);
}
&.gray {
@include button-color($gray);
}
& + & {
//Button뒤에 Button이 올때만.
margin-left: 1rem;
}
&.fullWidth {
width: 100%;
justify-content: center;
& + & {
margin-left: 0;
margin-top: 1rem;
}
}
}
이제 App.js에서 우리가 만든 속성을 적용해서 불러와보자.
App.js
import React from "react";
import Button from "./components/Button";
import "./App.scss";
function App() {
return (
<div className="App">
<div className="buttons">
<Button size="large">Button</Button>
<Button>Button</Button>
<Button size="small">Button</Button>
</div>
<div className="buttons">
<Button size="large" color="gray">
Button
</Button>
<Button color="gray">Button</Button>
<Button size="small" color="gray">
Button
</Button>
</div>
<div className="buttons">
<Button size="large" color="pink">
Button
</Button>
<Button color="pink">Button</Button>
<Button size="small" color="pink">
Button
</Button>
</div>
<div className="buttons">
<Button
// outline={true} 혹은 outline={false}라고 써줘도 됨. outline이 있으면 true, 없으면 false 반환.
size="large"
outline
>
Button
</Button>
<Button color="pink" outline>
Button
</Button>
<Button size="small" color="gray" outline>
Button
</Button>
</div>
<div className="buttons">
<Button size="large" fullWidth>
Button
</Button>
<Button size="large" color="pink" fullWidth>
Button
</Button>
<Button size="large" color="gray" fullWidth>
Button
</Button>
</div>
</div>
);
}
export default App;
잘 구동되는 것을 볼 수 있다.
버튼에 …rest props 전달하기
먼저 왜 …rest를 써야하는지 알아보자. 우리가 App.js에서 버튼에 onClick이나, onMouseMove라는 기능을 주었다고 가정했을때, 이 기능들을 Button.js에서 받아와서 적용해주어야 구동이 가능하다.
App.js 안에서의 button컴포넌트 일부
<Button
size="large"
color="gray"
fullWidth
onClick={() => {
console.log("클릭");
}}
onMouseMove={() => {
console.log("무브");
}}
>
Button
</Button>
이렇게 기능을 넣어주면 이걸 버튼 컴포넌트에서 받아와 연결해주는게 있어야 하는데 보통은 이런식으로 한다.
Button.js 안에서의 function button
function Button({
children,
size,
color,
outline,
fullWidth,
onClick,
onMouseMove,
}) {
return (
<button
className={classNames("Button", size, color, {
outline,
fullWidth,
})}
onClick={onClick} //이런식으로 연결
onMouseMove={onMouseMove} //이런식으로 연결
>
{children}
</button>
);
}
위와 같이 Button.js에서도 onClick과 onMouseMove도 연결해주어야 한다. 그런데 매번 이렇게 기능을 추가할때마다 컴포넌트로 넘어와서 기능을 넣어주는 것이 불편하다면 아래와 같이 …rest로 쉽게 구현할 수 있다.
function Button({ children, size, color, outline, fullWidth, ...rest }) {
return (
<button
className={classNames("Button", size, color, {
//이 둘은 true or false만 있기때문에 객체형태로 받아와준다고함.
outline,
fullWidth,
})}
{...rest}
>
{children}
</button>
);
}
여기서 한가지만 더 추가하자면, App.js 내에서 버튼을 커스터마이징 할 경우를 위해서 className도 받아와주면 더 완벽해질 수 있다.
function Button({
children,
size,
color,
outline,
fullWidth,
className,
...rest
}) {
//className 추가
console.log(rest);
return (
<button
className={classNames(
"Button",
size,
color,
{
outline,
fullWidth,
},
className //App에서 커스터마이징 클래스 이름이 생성될 경우 받아올 수 있도록 className 속성도 넣어주면 좋다.
)}
{...rest}
>
{children}
</button>
);
}
className이 겹치지 않게 작성하는 팁!
전체 프로젝트안에서 컴포넌트와 클래스명을 보여주면서 예시를 들어줬으면 더 좋았을 것 같은 개인적인 아쉬움이….
오늘은 여기까지..
시청 영상 31강 04~06까지
프론트엔드 개발 올인원 패키지 with React Online. 👉 https://bit.ly/31Cf1hp
Comments