WINK-(Web & App)/React.js 스터디

[2025 1학기 React.js 스터디] 이승준 #5주차

dltmdwns0512 2025. 5. 22. 20:01
반응형

안녕하세요 긴말말고 시작할게요! 

Sass

sass에서는 두가지 확장자 (.scss/.sass)를 지원합니다. 보통 scss 문법이 더 많이 사용됩니다.

우선 기본적인 설정을 해주고

이렇게 Button.js를 만져줬습니다.

근데 사실 이렇게 하면 안되고 defaultProps를 지우고 매개변수에 기본으로 넣어줘야합니다.

여기서 className에 CSS 클래스 이름을 동적으로 넣어주려면

className={['Button', size].join(' ')}

이렇게 처리할 수도 있습니다.

또는

className={`Button ${size}`}

하지만, 조건부로 CSS 클래스를 넣어주고 싶을때 이렇게 문자열을 직접 조합해주는 것 보다 classnames 라는 라이브러리를 사용하는 것이 훨씬 편합니다.

classNames 를 사용하면 다음과 같이 조건부 스타일링을 할 때 함수의 인자에 문자열, 배열, 객체 등을 전달하여 손쉽게 문자열을 조합 할 수 있습니다.

이런식으로 말이죠

이제 Button.js에서 사용해볼건데요,

이런식으로 해주면 props로 받은 props 값이 button 태그의 className으로 전달이 됩니다. 이에따라 Button.scss에서 스타일을 지정해줘 보겠습니다.

이런식으로 했는데 .Button안에 &.large medium..이 의미하는것은 .Button.large, .Button.medium을 의미한다.

이제 & + &가 뭐냐면 .Button + .Button을 의미하는데, 이 의미는 함께 있으면 우측에 있는 버튼에 margin-left를 설정하는 것입니다.

Button.js에서 props에 color을 설정해주었고, Button.scss에서 이제 color을 좀 만져줘보면,

이렇게 Button.scss를 만져줬는데, 겹치는 코드가 있는데, 이럴때 Sass의 mixin이라는 기능을 사용하면 쉽게 재사용가능합니다.

이런식으로 @mixin button-color() {}로 묶어서 겹치는 코드를 작성해주고, 뒤에 그 코드를 @include button-color(색상)으로 작성해주었다. 이런식으로 해주면 훨씬 관리하기 쉽다고 합니다. 그러고 App.js를 만져줘서 렌더링해주면 됩니다.

맨왼쪽 버튼들이 너무 붙어있는 측면이 있으니, App.scss를 만져주겠습니다.

이런식으로 아까도 사용했던건데, .buttons + .buttons로 margin을 줬습니다.

Outline 옵션 만들기

Button.js

아까랑 똑같이 outline 값을 props로 받아와서 객체 안에 집어넣은다음에 className()에 포함시켜줬는데요, 이렇게 하면 outline 값이 true일때만 button에 outline 스타일이 적용됩니다.

이렇게 mixing을 사용해서 outline을 설정해주었습니다. 그러고 렌더링해주었습니다.

전체 너비 차지하는 옵션

이번에는 fullWidth라는 옵션이 있으면 버튼이 전체 너비를 차지하도록 구현을 해보겠습니다.

outline에서 하는것처럼 props에 넣어주고 className에 fullWidth를 outline과 같이 넣어주겠습니다. 그리고 {}는 참고로 객체로서 안에 값이 true면 key에 포함된다. 

이런식으로 fullWidth 옵션을 만들어주고 width를 100%로 해서 꽉차게 만들어줬다.

이제 렌더링을 해주면

이렇게 나옵니다..

...rest props 전달하기 

버튼 컴포넌트에 onClick을 설정해주고 싶다면 어떻게 해야할까요. 일단 Button.js을 만져줘보면, 

이렇게 onClick={onClick} 이벤트를 관리할때는 이렇게 넣어주고 만약 onMouseMove 이벤트를 관리하고 싶으면

이렇게 필요한 이벤트가 있을 때 마다 매번 이렇게 넣어주는건 너무 귀찮습니다. 이러한 문제를 해결하기위해 spread와 rest문법을 사용해줍니다. 이 문법은 주로 배열과 객체, 함수의 파라미터, 인자를 다룰 때 사용합니다. 

Button.js를 ...rest를 사용해서 미리 지정한 값들 외에 값들을 ...rest에 모아주고, button태그에 ...rest를 해주면 rest 안에 있는 값들을 모두 button태그에 설정을 해줍니다.

이렇게 onClick을 그냥 태그에 지정해줘도 ...rest 객체에 들어가서 onClick이 잘 호출됩니다.

이 문법은 컴포넌트가 어떤 props를 받을 지는 확실치 않지만 그대로 다른 컴포넌트나 HTML 태그에 전달해주어야 하는 상황에 사용하면 됩니다.

 

정리를 해보자면 매번 버튼을 만들때마다 새로운 컴포넌트를 만들게 아니라 위와 같이 다양한 옵션을 넣을 수 있게 해서 그때 그때 커스터마이징 해서 사용하는 것이 효율적입니다.

 

CSS Module

CSS Module이라는 기술을 사용하면, CSS 클래스가 중첩되는 것을 완벽히 방지할 수 있다. CRA(Create React App)로 만든 환경에서 CSS Module을 사용할 때에는, CSS 파일의 확장자를 .module.css로 하면 됩니다. 리액트 컴포넌트 파일에서 해당 CSS 파일을 불러올 때 CSS 파일에 선언한 클래스 이름이 모두 고유해집니다.

예를 들어보겠습니다

 

이렇게 Box.module.css을 설정해주었구요, Box 컴포넌트를 만들면 아래와같이 작성해줍니다.

Box.js

이렇게 className을 설정 할 때에는 styles.Box 이렇게 import해서 불러온 styles 객체 안에 있는 값을 참조해야합니다.

  • 고유한 클래스 이름 생성: 다른 컴포넌트나 외부 CSS와 클래스 이름 충돌 없이 스타일 관리 가능.
  • 중복 걱정 없음: 기존 프로젝트(CSS 있는 레거시 프로젝트)에 리액트 도입 시 유용.
  • 네이밍 규칙 필요 없음: 복잡한 클래스 네이밍 컨벤션 없이도 안전하게 스타일링 가능.

이제 CSS Module 기술을 사용하여 커스텀 체크박스 컴포넌트를 만드는 방법을 배워보도록 하겠습니다.



여기서 ...rest를 사용하는 이유는 CheckBox 컴포넌트에게 전달할 다른 매개변수들을 그대로 input에게 넣어주기 위해서입니다.

그리고 이제 렌더링을 위해서 App.js를 만져주겠습니다.

근데 이렇게 실행해보면

이렇게 뜨는데 체크됨을 눌러도 체크가 됩니다 이 이유는 위에 CheckBox.js에서 input과 체크됨 체크안됨이 같이 label로 묶였기 때문에 그런현상이 발생합니다.

ChckBox.js

이렇게 수정을 해주면, 아이콘이 나타납니다. 그리고 CheckBox.module.css

위에서 배웠다시피 CSS Module을 작성 할때는 CSS 클래스 이름이 중복되는 일이 없으니, 단순한 .icon같은 이름을 사용해도 됩니다.

이제 CheckBox.js 에서 사용을 해볼게욤

이렇게 해줬는데 자꾸 에러가 떠서.... 왜그런지는 모르겠습니다.. 분명 CheckBox.module.css가 있는데 왜 resolve가 안되는지 모르겠슴다..

일단 CSS Module을 사용 할 때는 styles.icon같은 식으로 객체안에 있는 값을 조회해야 하는데, 만약 클래스 이름에 -가 들어가 있으면 styles['my-class']이렇게 사용해야 합니다. 여러가지가 있으면 ${styles.one} ${styles.two} 이렇게 해야합니다. Sass를 배울 때 썼었던 classnames 라이브러리에는 bind 기능이 있는데, 이걸 사용하면 CSS Module을 좀더 편하게 사용 가능합니당.

 

이런식으로 CheckBox.js를 수정해줬는데 classnames의 bind기능을 사용하면 css 클래스 이름을 지정해줄때 cx('클래스이름')과 같이 사용가능합니다.

 

기타 내용

CSS Module은 Sass에서도 사용 할 수 있다. 확장자를 .module.scss로 바꿔주면 된다.

전역적 클래스이름 사용

:global .my-global-name {

}

 

Sass에서는

:global {
  .my-global-name {

  }
}

CSS Module 사용하지 않는 곳에서 특정 클래스에서만 고유 이름을 만들어서 사용하고 싶으면

:local .make-this-local {

}

Sass에서는

:local {
  .make-this-local {

  }
}

 

Styled-components

JS 안에서 CSS를 사용하게 해주는 라이브러리이다. 

Tagged Template Literal

이 문법을 짚고 넘어가면 styled-components 작동방식에 대해 더 잘 이해할 수 있다고 하네욤..

우리가 Template Literal을 사용할때 ${}안에 객체나 함수를 넣게되면 어떻게 될까.

const object = { a: 1 };
const text = `${object}`
console.log(text);
// "[object Object]"

위에 예시는 객체를 넣은 예시다. 이때 출력값은 object Object가 나온다는데 이해가 안돼서 봤더니 toString 메서드가 자동으로 호출되어서 사실상 const text = String(object)로 되는거나 마찬가지이다.

함수의 예시도 한번 살펴보겠다.

const fn = () => true
const msg = `${fn}`;
console.log(msg);
// "() => true"

이것도 마찬가지로 함수를 객체로 인식해서 toString 매서드가 자동으로 호출되어 소스코드 중 일부 그대로가 출력된다.

그래서 만약에, 우리가 Template Literal 을 사용하면서도, 그 내부에 넣은 자바스크립트 값을 조회하고 싶을때는 Tagged Template Literal을 사용하면 된다.

const red = '빨간색';
const blue = '파란색';
function favoriteColors(texts, ...values) {
  console.log(texts);
  console.log(values);
}
favoriteColors`제가 좋아하는 색은 ${red}과 ${blue}입니다.`

코드를 보면 파라미터의 rest 문법이 사용되었다. tagged template literal을 보면 '제가 좋아하는 색은 과 입니다.'가 texts로 저장되고 ...values에 red와 blue 가 저장됩니다. 그래서 ${}를 통해 넣어준 자바스크립트 값을 따로 따로 볼 수 있다. 

const StyledDiv = styled`
  background: ${props => props.color};
`;

이렇게 props로 받아서 style을 지정해줄 수도 있습니다.

function sample(texts, ...fns) {
  const mockProps = {
    title: '안녕하세요',
    body: '내용은 내용내용 입니다.'
  };
  return texts.reduce((result, text, i) => `${result}${text}${fns[i] ? fns[i](mockProps) : ''}`, '');
}
sample`
  제목: ${props => props.title}
  내용: ${props => props.body}
`
/*
"
  제목: 안녕하세요
  내용: 내용은 내용내용 입니다.
"
*/

이렇게 ${}안에 함수를 넣어서 해당 함수를 사용해줄 수 있습니다.

이제 styled components를 이용해서 실습을 해보도록 하겠습니다. App.js를 만져줬습니다.

import React from 'react';
import styled from 'styled-components';

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

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

export default App;

이렇게 styled.div로 스타일이 붙혀져있는 div를 만들어주고 background에 props => props.color || 'black'로 color이 없으면 black으로 되었고, Circle color='blue'로 색깔을 줘서 black말고 blue로 지정되었다.

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

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

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

export default App;

이렇게 css코드를 조건부로 보여주고 싶으면 css를 사용해야한다. props.huge && css'이렇게 css를 불러와줘야한다. 그래야 스타일 내부에서도 다른 props를 조회 할 수 있다.

 

Button 만들기

일단 왼쪽부터 차례대로 Button.js, App.js를 이렇게 적어주었습니다. 

 

Polished의 스타일 관련 유틸 함수 사용하기

Sass를 사용 할 때는 lighten() 혹은 darken()같은 함수를 사용해서 바꿀 수 있었는데, CSS in JS에서도 비슷한걸 사용하고싶으면 polished를 사용하면 됩니다.(라이브러리)

lighten이랑 darken을 import해주고 사용해주었다.

이제 버튼 색깔을 바꿔보겠습ㅂ니다. ThemeProvider라는 기능을 사용해서 styled-components로 만드는 모든 컴포넌트에서 사용 가능한 전역적인 값을 설정해보겠습니다.  App.js를 만져보겠습니다.

이렇게 설정해주면 ThemeProvider 내부에 palette안에 값들을 조회해서 사용할 수 있다.한번 Button.js에서 사용해보겠다.

지금은 무조건 selected값을 blue를 가르키게 했는데, 이 부분을 Button 컴포넌트가 color을 props를 받아와서 색상을 설정하게 해보겠습니다.

이렇게 props.theme.palette[props.color]로 해주고 Button({color = 'blue'})로 해서 기본색상을 blue로 설정해주었습니다.

그리고 App.js를 만져줘서 회색, 핑크색 버튼을 렌더링해주면

이렇게 됩니다. ㅎ 근데 우리가 옛날에 배운 비구조화 할당 문법을 사용해서도 할 수 있는데, 

이런식으로 비구조화 할당 문법을 사용해줘서 일일이 앞에 props를 안붙혀도 되게 해도 됩니다. 근데

이런식으로 색상에 관련된 코드를 분리해서 작성해줄 수도 있습니다. 이 방식은 유지보수가 쉬워진다는 장점이 있습니다. 이렇게 세가지 스타일의 코드를 보여드렸는데요, 모두 나타나는 버튼의 스타일은 동일하지만 코드 작성 방식만 다른것입니다.

버튼의 크기 다양하게 하기

우선 아까 색상 스타일 지정했던것처럼 크기관련 코드를 분리하는 방식을 사용해서 작성해주었습니다. 이제 이렇게 크기를 해줬으면 렌더링하여 이렇게 만들어둔 사이즈를 지정해줘보겠습니다.

우선 이런식으로 렌더링해주었구요, 결과값을 보여드리겠습니다.

이렇게 나오네요..

이렇게 위에서 계속 크기나 색상 구현했던것처럼 props를 받아와서 설정해주었다. 이제 렌더링해주면

이렇게되는데 흠 원래 위에 버튼들은 공백이 있어야 말이되는ㄴ데 이게 fullWidthStyle이 영향을 미치긴 하는것같은데 왜 안되는지 모르겠습니다.. 검색을 열심히 해봤으나.. 

Dialog 만들기

일단 Dialog.js를 만들어주고 렌더링해주었는데..

이렇게 아까랑 비슷하게 fullWidth의 영향을 받네요.... 이게 어떻게 되는지 모르겠어요..

일단 넘어가고 아 뒤에 shortmargin을 지정해주는데,

 

이렇게 그냥 margin-top에 0을 줘서 아까같이 fullWidth의 영향을 받던거를 shortMarginButton이 덮어쓰게 만들었다. 그 다음에는 App 컴포넌트에서 useState를 사용해서 맨아래에 있는 큰 버튼을 누르면 Dialog가 보여지도록 onConfirm, onCancel, visibel 값을 설정해서 설정을 해주었다.

이런식으로 말이죠 그래서 실행해보면 

왼쪽이 기본이고 삭제누르면 오른쪽처럼 됩니다.

트랜지션 구현하기

트랜지션 효과를 적용해볼건데, 트랜지션 효과를 적용 할 때는 CSS Keyframe을 사용하고, styled-components에서 이를 사용할 때는 keyframes라는 유틸을 사용한다. 여기서는 useEffect를 사용해서 Dialog가 서서히 나타나는 FadeIn과 아래로부터 위로 올라오는 slideUp효과를 줘볼게요

 

사실 이것들은 다 keyframes 유틸을 이용해서 구현한거라 여기서 마치도록 하겠습니다 감사합니다!!!!

반응형